Skip to content

PERF-269: Optimization: DerivedColumn class so decrease allocation size of MappedColumn #382

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Orm/Xtensive.Orm/Orm/Rse/AggregateColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Xtensive.Orm.Rse
/// Aggregate column of the <see cref="RecordSetHeader"/>.
/// </summary>
[Serializable]
public sealed class AggregateColumn : Column
public sealed class AggregateColumn : DerivedColumn
{
private const string ToStringFormat = "{0} = {1} on ({2})";

Expand Down Expand Up @@ -70,19 +70,19 @@ public AggregateColumn(AggregateColumnDescriptor descriptor, ColNum index, Type
#region Clone constructors

private AggregateColumn(AggregateColumn column, string newName)
: base(newName, column.Index, column.Type, column)
: base(newName, column.Index, column.Type, column.Origin)
{
AggregateType = column.AggregateType;
SourceIndex = column.SourceIndex;
}

private AggregateColumn(AggregateColumn column, ColNum newIndex)
: base(column.Name, newIndex, column.Type, column)
: base(column.Name, newIndex, column.Type, column.Origin)
{
AggregateType = column.AggregateType;
SourceIndex = column.SourceIndex;
}

#endregion
}
}
}
8 changes: 4 additions & 4 deletions Orm/Xtensive.Orm/Orm/Rse/CalculatedColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace Xtensive.Orm.Rse
/// Calculated column of the <see cref="RecordSetHeader"/>.
/// </summary>
[Serializable]
public sealed class CalculatedColumn : Column
public sealed class CalculatedColumn : DerivedColumn
{
private const string ToStringFormat = "{0} = {1}";

Expand Down Expand Up @@ -63,17 +63,17 @@ public CalculatedColumn(CalculatedColumnDescriptor descriptor, ColNum index)
#region Clone constructors

private CalculatedColumn(CalculatedColumn column, string newName)
: base(newName, column.Index, column.Type, column)
: base(newName, column.Index, column.Type, column.Origin)
{
Expression = column.Expression;
}

private CalculatedColumn(CalculatedColumn column, ColNum newIndex)
: base(column.Name, newIndex, column.Type, column)
: base(column.Name, newIndex, column.Type, column.Origin)
{
Expression = column.Expression;
}

#endregion
}
}
}
153 changes: 64 additions & 89 deletions Orm/Xtensive.Orm/Orm/Rse/Column.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,109 +4,84 @@
// Created by: Elena Vakhtina
// Created: 2008.09.09

using System;
namespace Xtensive.Orm.Rse;


namespace Xtensive.Orm.Rse
/// <summary>
/// Base class for any column of the <see cref="RecordSetHeader"/>.
/// </summary>
[Serializable]
public abstract class Column(string name, ColNum index, Type type) : IEquatable<Column>
{
/// <summary>
/// Base class for any column of the <see cref="RecordSetHeader"/>.
/// Gets origin <see cref="Column"/> for this instance.
/// </summary>
[Serializable]
public abstract class Column : IEquatable<Column>
{
private const string ToStringFormat = "{0} {1} ({2})";

/// <summary>
/// Gets origin <see cref="Column"/> for this instance.
/// </summary>
public Column Origin { get; private set; }

/// <summary>
/// Gets the column name.
/// </summary>
public string Name { get; private set; }

/// <summary>
/// Gets the column index.
/// </summary>
public ColNum Index { get; }

/// <summary>
/// Gets the column type.
/// </summary>
public Type Type { get; private set; }

#region Equals, GetHashCode, ==, !=
public virtual Column Origin => this;

/// <inheritdoc/>
public bool Equals(Column other) =>
other is not null && (ReferenceEquals(this, other) || Name == other.Name);
/// <summary>
/// Gets the column name.
/// </summary>
public string Name { get; } = name;

/// <inheritdoc/>
public override bool Equals(object obj) => obj is Column other && Equals(other);
/// <summary>
/// Gets the column index.
/// </summary>
public ColNum Index { get; } = index;

/// <inheritdoc/>
public override int GetHashCode() => Name.GetHashCode();
/// <summary>
/// Gets the column type.
/// </summary>
public Type Type { get; } = type;

/// <summary>
/// Implements the operator ==.
/// </summary>
/// <param name="left">The left.</param>
/// <param name="right">The right.</param>
/// <returns>
/// The result of the operator.
/// </returns>
public static bool operator ==(Column left, Column right) => left?.Equals(right) ?? right is null;
/// <inheritdoc/>
public bool Equals(Column other) =>
other is not null && (ReferenceEquals(this, other) || Name == other.Name);

/// <summary>
/// Implements the operator !=.
/// </summary>
/// <param name="left">The left.</param>
/// <param name="right">The right.</param>
/// <returns>
/// The result of the operator.
/// </returns>
public static bool operator !=(Column left, Column right) => !(left == right);
/// <inheritdoc/>
public override bool Equals(object obj) => obj is Column other && Equals(other);

#endregion
/// <inheritdoc/>
public override int GetHashCode() => Name.GetHashCode();

/// <inheritdoc/>
public override string ToString()
{
return string.Format(ToStringFormat, Type.Name, Name, Index);
}
/// <summary>
/// Implements the operator ==.
/// </summary>
/// <param name="left">The left.</param>
/// <param name="right">The right.</param>
/// <returns>
/// The result of the operator.
/// </returns>
public static bool operator ==(Column left, Column right) => left?.Equals(right) ?? right is null;

/// <summary>
/// Creates clone of the column, but with another <see cref="Index"/>.
/// </summary>
/// <param name="newIndex">The new index value.</param>
/// <returns>Clone of the column, but with another <see cref="Index"/>.</returns>
public abstract Column Clone(ColNum newIndex);
/// <summary>
/// Implements the operator !=.
/// </summary>
/// <param name="left">The left.</param>
/// <param name="right">The right.</param>
/// <returns>
/// The result of the operator.
/// </returns>
public static bool operator !=(Column left, Column right) => !(left == right);

/// <summary>
/// Creates clone of the column, but with another <see cref="Name"/>.
/// </summary>
/// <param name="newName">The new name value.</param>
/// <returns>Clone of the column, but with another <see cref="Name"/>.</returns>
public abstract Column Clone(string newName);
/// <inheritdoc/>
public override string ToString() => $"{Type.Name} {Name} ({Index})";

/// <summary>
/// Creates clone of the column, but with another <see cref="Index"/>.
/// </summary>
/// <param name="newIndex">The new index value.</param>
/// <returns>Clone of the column, but with another <see cref="Index"/>.</returns>
public abstract Column Clone(ColNum newIndex);

// Constructors
/// <summary>
/// Creates clone of the column, but with another <see cref="Name"/>.
/// </summary>
/// <param name="newName">The new name value.</param>
/// <returns>Clone of the column, but with another <see cref="Name"/>.</returns>
public abstract Column Clone(string newName);
}

/// <summary>
/// Initializes a new instance of this class..
/// </summary>
/// <param name="name"><see cref="Name"/> property value.</param>
/// <param name="index"><see cref="Index"/> property value.</param>
/// <param name="type"><see cref="Type"/> property value.</param>
/// <param name="originalColumn">Original column.</param>
protected Column(string name, ColNum index, Type type, Column originalColumn)
{
Name = name;
Index = index;
Type = type;
Origin = originalColumn is null ? this : originalColumn.Origin;
}
}
public abstract class DerivedColumn(string name, ColNum index, Type type, Column origin)
: Column(name, index, type)
{
public override Column Origin => origin ?? this;
}
124 changes: 46 additions & 78 deletions Orm/Xtensive.Orm/Orm/Rse/MappedColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,97 +4,65 @@
// Created by: Alexey Kochetov
// Created: 2007.09.21

using System;
using Xtensive.Orm.Model;

namespace Xtensive.Orm.Rse
namespace Xtensive.Orm.Rse;

/// <summary>
/// Mapped column of the <see cref="RecordSetHeader"/>.
/// </summary>
[Serializable]
public class MappedColumn(ColumnInfoRef columnInfoRef, string name, ColNum index, Type type)
: Column(name, index, type)
{
/// <summary>
/// Mapped column of the <see cref="RecordSetHeader"/>.
/// Gets the reference that describes a column.
/// </summary>
[Serializable]
public sealed class MappedColumn : Column
{
private const string ToStringFormat = "{0} = {1}";

/// <summary>
/// Gets the reference that describes a column.
/// </summary>
public ColumnInfoRef ColumnInfoRef { get; }

/// <inheritdoc/>
public override string ToString()
{
return string.Format(ToStringFormat, base.ToString(), ColumnInfoRef);
}

/// <inheritdoc/>
public override Column Clone(ColNum newIndex)
{
return new MappedColumn(ColumnInfoRef, Name, newIndex, Type);
}
public ColumnInfoRef ColumnInfoRef { get; } = columnInfoRef;

/// <inheritdoc/>
public override Column Clone(string newName)
{
return new MappedColumn(this, newName);
}
/// <inheritdoc/>
public override string ToString() => $"{base.ToString()} = {ColumnInfoRef}";

// Constructors
/// <inheritdoc/>
public override Column Clone(ColNum newIndex) => new MappedColumn(ColumnInfoRef, Name, newIndex, Type);

#region Basic constructors
/// <inheritdoc/>
public override Column Clone(string newName) => new DerivedMappedColumn(newName, Index, Type, Origin, ColumnInfoRef);

/// <summary>
/// Initializes a new instance of this class.
/// </summary>
/// <param name="name"><see cref="Column.Name"/> property value.</param>
/// <param name="index"><see cref="Column.Index"/> property value.</param>
/// <param name="type"><see cref="Column.Type"/> property value.</param>
public MappedColumn(string name, ColNum index, Type type)
: this(default, name, index, type)
{
}
// Constructors

/// <summary>
/// Initializes a new instance of this class.
/// </summary>
/// <param name="columnInfoRef"><see cref="ColumnInfoRef"/> property value.</param>
/// <param name="index"><see cref="Column.Index"/> property value.</param>
/// <param name="type"><see cref="Column.Type"/> property value.</param>
public MappedColumn(ColumnInfoRef columnInfoRef, ColNum index, Type type)
: this(columnInfoRef, columnInfoRef.ColumnName, index, type)
{
}
#region Basic constructors

/// <summary>
/// Initializes a new instance of this class.
/// </summary>
/// <param name="columnInfoRef"><see cref="ColumnInfoRef"/> property value.</param>
/// <param name="name"><see cref="Column.Name"/> property value.</param>
/// <param name="index"><see cref="Column.Index"/> property value.</param>
/// <param name="type"><see cref="Column.Type"/> property value.</param>
public MappedColumn(ColumnInfoRef columnInfoRef, string name, ColNum index, Type type)
: base(name, index, type, null)
{
ColumnInfoRef = columnInfoRef;
}

#endregion
/// <summary>
/// Initializes a new instance of this class.
/// </summary>
/// <param name="name"><see cref="Column.Name"/> property value.</param>
/// <param name="index"><see cref="Column.Index"/> property value.</param>
/// <param name="type"><see cref="Column.Type"/> property value.</param>
public MappedColumn(string name, ColNum index, Type type)
: this(default, name, index, type)
{
}

#region Clone constructors
/// <summary>
/// Initializes a new instance of this class.
/// </summary>
/// <param name="columnInfoRef"><see cref="ColumnInfoRef"/> property value.</param>
/// <param name="index"><see cref="Column.Index"/> property value.</param>
/// <param name="type"><see cref="Column.Type"/> property value.</param>
public MappedColumn(ColumnInfoRef columnInfoRef, ColNum index, Type type)
: this(columnInfoRef, columnInfoRef.ColumnName, index, type)
{
}

private MappedColumn(MappedColumn column, string newName)
: base(newName, column.Index, column.Type, column)
{
ColumnInfoRef = column.ColumnInfoRef;
}
#endregion

private MappedColumn(MappedColumn column, ColNum newIndex)
: base(column.Name, newIndex, column.Type, column)
{
ColumnInfoRef = column.ColumnInfoRef;
}
}

#endregion
}
// The purpose of this class is minimize allocation size of `MappedColumn`
// Non self-referencing `Origin` property is a rare case
internal sealed class DerivedMappedColumn(string name, ColNum index, Type type, Column origin, ColumnInfoRef columnInfoRef)
: MappedColumn(columnInfoRef, name, index, type)
{
public override Column Origin => origin ?? this;
}
Loading