forked from dotnet/machinelearning
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSimpleRow.cs
More file actions
158 lines (136 loc) · 6.16 KB
/
Copy pathSimpleRow.cs
File metadata and controls
158 lines (136 loc) · 6.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.ML.Internal.Utilities;
namespace Microsoft.ML.Data
{
/// <summary>
/// An implementation of <see cref="Row"/> that gets its <see cref="Row.Position"/>, <see cref="Row.Batch"/>,
/// and <see cref="Row.GetIdGetter"/> from an input row. The constructor requires a schema and array of getter
/// delegates. A <see langword="null"/> delegate indicates an inactive column. The delegates are assumed to be
/// of the appropriate type (this does not validate the type).
/// REVIEW: Should this validate that the delegates are of the appropriate type? It wouldn't be difficult
/// to do so.
/// </summary>
[BestFriend]
internal sealed class SimpleRow : WrappingRow
{
private readonly Delegate[] _getters;
private readonly Action _disposer;
public override Schema Schema { get; }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="schema">The schema for the row.</param>
/// <param name="input">The row that is being wrapped by this row, where our <see cref="Row.Position"/>,
/// <see cref="Row.Batch"/>, <see cref="Row.GetIdGetter"/>.</param>
/// <param name="getters">The collection of getter delegates, whose types should map those in a schema.
/// If one of these is <see langword="null"/>, the corresponding column is considered inactive.</param>
/// <param name="disposer">A method that, if non-null, will be called exactly once during
/// <see cref="IDisposable.Dispose"/>, prior to disposing <paramref name="input"/>.</param>
public SimpleRow(Schema schema, Row input, Delegate[] getters, Action disposer = null)
: base(input)
{
Contracts.CheckValue(schema, nameof(schema));
Contracts.CheckValue(input, nameof(input));
Contracts.Check(Utils.Size(getters) == schema.Count);
Contracts.CheckValueOrNull(disposer);
Schema = schema;
_getters = getters ?? new Delegate[0];
_disposer = disposer;
}
protected override void DisposeCore(bool disposing)
{
if (disposing)
_disposer?.Invoke();
}
public override ValueGetter<T> GetGetter<T>(int col)
{
Contracts.CheckParam(0 <= col && col < _getters.Length, nameof(col), "Invalid col value in GetGetter");
Contracts.Check(IsColumnActive(col));
if (_getters[col] is ValueGetter<T> fn)
return fn;
throw Contracts.Except("Unexpected TValue in GetGetter");
}
public override bool IsColumnActive(int col)
{
Contracts.Check(0 <= col && col < _getters.Length);
return _getters[col] != null;
}
}
/// <summary>
/// An <see cref="ISchema"/> that takes all column names and types as constructor parameters.
/// The columns do not have metadata.
/// </summary>
public abstract class SimpleSchemaBase : ISchema
{
protected readonly IExceptionContext Ectx;
private readonly string[] _names;
protected readonly ColumnType[] Types;
protected readonly Dictionary<string, int> ColumnNameMap;
public int ColumnCount => Types.Length;
protected SimpleSchemaBase(IExceptionContext ectx, params KeyValuePair<string, ColumnType>[] columns)
{
Contracts.CheckValueOrNull(ectx);
Ectx = ectx;
Ectx.CheckValue(columns, nameof(columns));
_names = new string[columns.Length];
Types = new ColumnType[columns.Length];
ColumnNameMap = new Dictionary<string, int>();
for (int i = 0; i < columns.Length; i++)
{
_names[i] = columns[i].Key;
Types[i] = columns[i].Value;
if (ColumnNameMap.ContainsKey(columns[i].Key))
throw ectx.ExceptParam(nameof(columns), $"Duplicate column name: '{columns[i].Key}'");
ColumnNameMap[columns[i].Key] = i;
}
}
public bool TryGetColumnIndex(string name, out int col)
{
return ColumnNameMap.TryGetValue(name, out col);
}
public string GetColumnName(int col)
{
Ectx.CheckParam(0 <= col && col < ColumnCount, nameof(col));
return _names[col];
}
public ColumnType GetColumnType(int col)
{
Ectx.CheckParam(0 <= col && col < ColumnCount, nameof(col));
return Types[col];
}
public IEnumerable<KeyValuePair<string, ColumnType>> GetMetadataTypes(int col)
{
Ectx.Assert(0 <= col && col < ColumnCount);
return GetMetadataTypesCore(col);
}
protected abstract IEnumerable<KeyValuePair<string, ColumnType>> GetMetadataTypesCore(int col);
public ColumnType GetMetadataTypeOrNull(string kind, int col)
{
Ectx.CheckParam(0 <= col && col < ColumnCount, nameof(col));
return GetMetadataTypeOrNullCore(kind, col);
}
protected abstract ColumnType GetMetadataTypeOrNullCore(string kind, int col);
public void GetMetadata<TValue>(string kind, int col, ref TValue value)
{
Ectx.CheckParam(0 <= col && col < ColumnCount, nameof(col));
GetMetadataCore(kind, col, ref value);
}
protected abstract void GetMetadataCore<TValue>(string kind, int col, ref TValue value);
}
public static class SimpleSchemaUtils
{
public static Schema Create(IExceptionContext ectx, params KeyValuePair<string, ColumnType>[] columns)
{
Contracts.CheckValueOrNull(ectx);
ectx.CheckValue(columns, nameof(columns));
var builder = new SchemaBuilder();
builder.AddColumns(columns.Select(kvp => new Schema.DetachedColumn(kvp.Key, kvp.Value)));
return builder.GetSchema();
}
}
}