< Summary

Class:GDX.DataTables.DataTableExtensions
Assembly:GDX
File(s):./Packages/com.dotbunny.gdx/GDX/DataTables/DataTableExtensions.cs
Covered lines:0
Uncovered lines:155
Coverable lines:155
Total lines:339
Line coverage:0% (0 of 155)
Covered branches:0
Total branches:0
Covered methods:0
Total methods:4
Method coverage:0% (0 of 4)

Coverage History

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
GetCellValueAsString(...)0%15603900%
SetCellValueFromString(...)0%2401500%
GetAllRowDescriptionsSortedByColumns(...)0%3421800%
GetComparer(...)0%2101400%

File(s)

./Packages/com.dotbunny.gdx/GDX/DataTables/DataTableExtensions.cs

#LineLine coverage
 1// Copyright (c) 2020-2024 dotBunny Inc.
 2// dotBunny licenses this file to you under the BSL-1.0 license.
 3// See the LICENSE file in the project root for more information.
 4
 5using System;
 6using System.Collections.Generic;
 7using System.Globalization;
 8using GDX.DataTables.ColumnSorters;
 9using UnityEngine;
 10using UnityEngine.UIElements;
 11
 12namespace GDX.DataTables
 13{
 14    /// <summary>
 15    ///     <see cref="DataTableBase" /> Based Extension Methods
 16    /// </summary>
 17    public static class DataTableExtensions
 18    {
 19        /// <summary>
 20        ///     Get the value of a cell in a <see cref="DataTableBase" />, as a <see cref="string" />.
 21        /// </summary>
 22        /// <param name="dataTable">The target Data Table to query for the value.</param>
 23        /// <param name="rowIdentifier">The unique row identifier.</param>
 24        /// <param name="columnIdentifier">The unique column identifier.</param>
 25        /// <param name="columnType">A hint as to the type of the column. If this is not provided a cost will be paid to
 26        /// <returns>The <see cref="string" /> value of the target row's column.</returns>
 27        public static string GetCellValueAsString(this DataTableBase dataTable, int rowIdentifier, int columnIdentifier,
 28            Serializable.SerializableTypes columnType = Serializable.SerializableTypes.Invalid)
 029        {
 30            // If type wasn't provided.
 031            if (columnType == Serializable.SerializableTypes.Invalid)
 032            {
 033                columnType = dataTable.GetColumnDescription(columnIdentifier).Type;
 034            }
 35
 036            switch (columnType)
 37            {
 38                case Serializable.SerializableTypes.String:
 039                    return dataTable.GetString(rowIdentifier, columnIdentifier);
 40                case Serializable.SerializableTypes.Char:
 041                    return dataTable.GetChar(rowIdentifier, columnIdentifier).ToString();
 42                case Serializable.SerializableTypes.Bool:
 043                    return dataTable.GetBool(rowIdentifier, columnIdentifier).ToString();
 44                case Serializable.SerializableTypes.SByte:
 045                    return dataTable.GetSByte(rowIdentifier, columnIdentifier).ToString();
 46                case Serializable.SerializableTypes.Byte:
 047                    return dataTable.GetByte(rowIdentifier, columnIdentifier).ToString();
 48                case Serializable.SerializableTypes.Short:
 049                    return dataTable.GetShort(rowIdentifier, columnIdentifier).ToString();
 50                case Serializable.SerializableTypes.UShort:
 051                    return dataTable.GetUShort(rowIdentifier, columnIdentifier).ToString();
 52                case Serializable.SerializableTypes.Int:
 053                    return dataTable.GetInt(rowIdentifier, columnIdentifier).ToString();
 54                case Serializable.SerializableTypes.UInt:
 055                    return dataTable.GetUInt(rowIdentifier, columnIdentifier).ToString();
 56                case Serializable.SerializableTypes.Long:
 057                    return dataTable.GetLong(rowIdentifier, columnIdentifier).ToString();
 58                case Serializable.SerializableTypes.ULong:
 059                    return dataTable.GetULong(rowIdentifier, columnIdentifier).ToString();
 60                case Serializable.SerializableTypes.Float:
 061                    return dataTable.GetFloat(rowIdentifier, columnIdentifier).ToString(CultureInfo.InvariantCulture);
 62                case Serializable.SerializableTypes.Double:
 063                    return dataTable.GetDouble(rowIdentifier, columnIdentifier).ToString(CultureInfo.InvariantCulture);
 64                case Serializable.SerializableTypes.Vector2:
 065                    return dataTable.GetUShort(rowIdentifier, columnIdentifier).ToString();
 66                case Serializable.SerializableTypes.Vector3:
 067                    return dataTable.GetVector3(rowIdentifier, columnIdentifier).ToString();
 68                case Serializable.SerializableTypes.Vector4:
 069                    return dataTable.GetVector4(rowIdentifier, columnIdentifier).ToString();
 70                case Serializable.SerializableTypes.Vector2Int:
 071                    return dataTable.GetVector2Int(rowIdentifier, columnIdentifier).ToString();
 72                case Serializable.SerializableTypes.Vector3Int:
 073                    return dataTable.GetVector3Int(rowIdentifier, columnIdentifier).ToString();
 74                case Serializable.SerializableTypes.Quaternion:
 075                    return dataTable.GetQuaternion(rowIdentifier, columnIdentifier).ToString();
 76                case Serializable.SerializableTypes.Rect:
 077                    return dataTable.GetRect(rowIdentifier, columnIdentifier).ToString();
 78                case Serializable.SerializableTypes.RectInt:
 079                    return dataTable.GetRectInt(rowIdentifier, columnIdentifier).ToString();
 80                case Serializable.SerializableTypes.Color:
 081                    return dataTable.GetColor(rowIdentifier, columnIdentifier).ToString();
 82                case Serializable.SerializableTypes.LayerMask:
 083                    return dataTable.GetLayerMask(rowIdentifier, columnIdentifier).ToString();
 84                case Serializable.SerializableTypes.Bounds:
 085                    return dataTable.GetBounds(rowIdentifier, columnIdentifier).ToString();
 86                case Serializable.SerializableTypes.BoundsInt:
 087                    return dataTable.GetBoundsInt(rowIdentifier, columnIdentifier).ToString();
 88                case Serializable.SerializableTypes.Hash128:
 089                    return dataTable.GetHash128(rowIdentifier, columnIdentifier).ToString();
 90                case Serializable.SerializableTypes.Gradient:
 091                    return dataTable.GetGradient(rowIdentifier, columnIdentifier)?.ToString();
 92                case Serializable.SerializableTypes.AnimationCurve:
 093                    return dataTable.GetAnimationCurve(rowIdentifier, columnIdentifier)?.ToString();
 94                case Serializable.SerializableTypes.Object:
 095                    return dataTable.GetObject(rowIdentifier, columnIdentifier)?.ToString();
 96                case Serializable.SerializableTypes.EnumInt:
 097                    return dataTable.GetEnumInt(rowIdentifier, columnIdentifier).ToString();
 98            }
 99
 0100            return null;
 0101        }
 102
 103        /// <summary>
 104        ///     Set the value of a cell in a <see cref="DataTableBase" /> from a <see cref="string" /> value.
 105        /// </summary>
 106        /// <param name="dataTable">The target Data Table to set a value for.</param>
 107        /// <param name="rowIdentifier">The unique row identifier.</param>
 108        /// <param name="columnIdentifier">The unique column identifier.</param>
 109        /// <param name="newValue">The value to set.</param>
 110        /// <param name="columnType">A hint as to the type of the column. If this is not provided a cost will be paid to
 111        public static void SetCellValueFromString(this DataTableBase dataTable, int rowIdentifier, int columnIdentifier,
 112            string newValue,
 113            Serializable.SerializableTypes columnType = Serializable.SerializableTypes.Invalid)
 0114        {
 115            // If type wasn't provided.
 0116            if (columnType == Serializable.SerializableTypes.Invalid)
 0117            {
 0118                columnType = dataTable.GetColumnDescription(columnIdentifier).Type;
 0119            }
 120
 0121            switch (columnType)
 122            {
 123                case Serializable.SerializableTypes.String:
 0124                    dataTable.SetString(rowIdentifier, columnIdentifier, newValue);
 0125                    break;
 126                case Serializable.SerializableTypes.Char:
 0127                    dataTable.SetChar(rowIdentifier, columnIdentifier, newValue[0]);
 0128                    break;
 129                case Serializable.SerializableTypes.Bool:
 0130                    dataTable.SetBool(rowIdentifier, columnIdentifier,
 131                        bool.Parse(newValue));
 0132                    break;
 133                case Serializable.SerializableTypes.SByte:
 0134                    dataTable.SetSByte(rowIdentifier, columnIdentifier,
 135                        sbyte.Parse(newValue));
 0136                    break;
 137                case Serializable.SerializableTypes.Byte:
 0138                    dataTable.SetByte(rowIdentifier, columnIdentifier,
 139                        byte.Parse(newValue));
 0140                    break;
 141                case Serializable.SerializableTypes.Short:
 0142                    dataTable.SetShort(rowIdentifier, columnIdentifier,
 143                        short.Parse(newValue));
 0144                    break;
 145                case Serializable.SerializableTypes.UShort:
 0146                    dataTable.SetUShort(rowIdentifier, columnIdentifier,
 147                        ushort.Parse(newValue));
 0148                    break;
 149                case Serializable.SerializableTypes.Int:
 0150                    dataTable.SetInt(rowIdentifier, columnIdentifier, int.Parse(newValue));
 0151                    break;
 152                case Serializable.SerializableTypes.UInt:
 0153                    dataTable.SetUInt(rowIdentifier, columnIdentifier,
 154                        uint.Parse(newValue));
 0155                    break;
 156                case Serializable.SerializableTypes.Long:
 0157                    dataTable.SetLong(rowIdentifier, columnIdentifier,
 158                        long.Parse(newValue));
 0159                    break;
 160                case Serializable.SerializableTypes.ULong:
 0161                    dataTable.SetULong(rowIdentifier, columnIdentifier,
 162                        ulong.Parse(newValue));
 0163                    break;
 164                case Serializable.SerializableTypes.Float:
 0165                    dataTable.SetFloat(rowIdentifier, columnIdentifier,
 166                        float.Parse(newValue));
 0167                    break;
 168                case Serializable.SerializableTypes.Double:
 0169                    dataTable.SetDouble(rowIdentifier, columnIdentifier,
 170                        double.Parse(newValue));
 0171                    break;
 172            }
 0173        }
 174
 175#if UNITY_2022_2_OR_NEWER
 176
 177        /// <summary>
 178        ///     Sort <see cref="DataTableBase" /> rows based on the provided sorting parameters.
 179        /// </summary>
 180        /// <param name="dataTable">The target <see cref="DataTableBase" />.</param>
 181        /// <param name="columnIdentifiers">The column identifiers to use in order of priority.</param>
 182        /// <param name="columnTypes">The types of the given columns.</param>
 183        /// <param name="directions">The direction which the column should be used to calculate order.</param>
 184        /// <returns>A sorted array of <see cref="RowDescription" />, or null.</returns>
 185        public static RowDescription[] GetAllRowDescriptionsSortedByColumns(this DataTableBase dataTable,
 186            int[] columnIdentifiers,
 187            Serializable.SerializableTypes[] columnTypes, SortDirection[] directions)
 0188        {
 0189            RowDescription[] rows = dataTable.GetAllRowDescriptions();
 190
 0191            if (columnIdentifiers.Length != columnTypes.Length || columnTypes.Length != directions.Length)
 0192            {
 0193                Debug.LogError("Unable to sort, all arrays much have same length.");
 0194                return rows;
 195            }
 196
 197
 0198            int rowCount = dataTable.GetRowCount();
 0199            if (rowCount <= 1 || columnIdentifiers.Length == 0)
 0200            {
 0201                return rows;
 202            }
 203
 0204            bool multiSort = columnIdentifiers.Length > 1;
 205
 206            // Primary Sort Pass
 0207            List<int> needAdditionalSortingIdentifiers = new List<int>(rowCount);
 0208            IComparer<RowDescription> primaryComparer = GetComparer(columnTypes[0], dataTable, rowCount,
 209                columnIdentifiers[0], (int)directions[0], multiSort);
 0210            if (primaryComparer == null)
 0211            {
 0212                return rows;
 213            }
 214
 0215            Array.Sort(rows, 0, rowCount, primaryComparer);
 216
 217            // Multi column support
 0218            if (multiSort)
 0219            {
 0220                ColumnSorterBase primarySorter = (ColumnSorterBase)primaryComparer;
 0221                needAdditionalSortingIdentifiers.AddRange(primarySorter.EqualIdentifiers);
 0222                if (needAdditionalSortingIdentifiers.Count > 0)
 0223                {
 224                    // We have additional sorting to be done and have additional sorter options
 0225                    int sorterIndex = 1;
 226
 227                    // Iterate till we have nothing to do
 0228                    while (needAdditionalSortingIdentifiers.Count > 0 && sorterIndex < columnIdentifiers.Length)
 0229                    {
 0230                        int currentSortingCount = needAdditionalSortingIdentifiers.Count;
 231
 232                        // Build list
 0233                        List<int> startIndex = new List<int>(currentSortingCount);
 0234                        List<int> stopIndex = new List<int>(currentSortingCount);
 0235                        bool insideOfRange = false;
 0236                        for (int i = 0; i < rowCount; i++)
 0237                        {
 0238                            ref RowDescription currentRow = ref rows[i];
 239
 0240                            if (needAdditionalSortingIdentifiers.Contains(currentRow.Identifier) && !insideOfRange)
 0241                            {
 0242                                startIndex.Add(i);
 0243                                insideOfRange = true;
 0244                                continue;
 245                            }
 246
 0247                            if (insideOfRange && !needAdditionalSortingIdentifiers.Contains(currentRow.Identifier))
 0248                            {
 0249                                stopIndex.Add(i - 1);
 0250                                insideOfRange = false;
 0251                            }
 0252                        }
 253
 254                        // If the last item
 0255                        if (insideOfRange)
 0256                        {
 0257                            stopIndex.Add(rowCount - 1);
 0258                        }
 259
 260                        // Clear the scratch pad now that we've created our actual indices
 0261                        needAdditionalSortingIdentifiers.Clear();
 262
 0263                        int indexCount = startIndex.Count;
 0264                        for (int i = 0; i < indexCount; i++)
 0265                        {
 0266                            int length = stopIndex[i] - startIndex[i] + 1;
 0267                            IComparer<RowDescription> secondaryComparer = GetComparer(columnTypes[sorterIndex],
 268                                dataTable, length,
 269                                columnIdentifiers[sorterIndex], (int)directions[sorterIndex], true);
 270
 0271                            if (secondaryComparer == null)
 0272                            {
 0273                                break;
 274                            }
 275
 0276                            Array.Sort(rows, startIndex[i], length, secondaryComparer);
 0277                            ColumnSorterBase secondarySorter = (ColumnSorterBase)secondaryComparer;
 0278                            needAdditionalSortingIdentifiers.AddRange(secondarySorter.EqualIdentifiers);
 0279                        }
 280
 281                        // Next sorter it appears
 0282                        sorterIndex++;
 0283                    }
 0284                }
 0285            }
 286
 0287            return rows;
 0288        }
 289
 290        /// <summary>
 291        ///     Get the appropriate <see cref="IComparer{T}" /> for a <see cref="DataTableBase" /> column.
 292        /// </summary>
 293        /// <param name="type">The <see cref="Serializable.SerializableTypes" /> of the column.</param>
 294        /// <param name="dataTable">The target <see cref="DataTableBase" /> the column belongs to.</param>
 295        /// <param name="rowCount">
 296        ///     The number of values to be sorted. This is only used to help pre-size an internal counter used
 297        ///     for multi-sort.
 298        /// </param>
 299        /// <param name="columnIdentifier">The identifier of the column being sorted.</param>
 300        /// <param name="direction">The direction to sort.</param>
 301        /// <param name="supportMultiSort">Should the extra multi-sort work be done?</param>
 302        /// <returns>A qualified <see cref="IComparer{T}" /> for the column.</returns>
 303        static IComparer<RowDescription> GetComparer(Serializable.SerializableTypes type, DataTableBase dataTable,
 304            int rowCount, int columnIdentifier, int direction, bool supportMultiSort = false)
 0305        {
 0306            if (columnIdentifier == -1 && type == Serializable.SerializableTypes.String)
 0307            {
 0308                return new RowNameColumnSorter(dataTable, rowCount, -1, direction, supportMultiSort);
 309            }
 310
 311            // Default sorters
 0312            switch (type)
 313            {
 314                case Serializable.SerializableTypes.Float:
 0315                    return new FloatColumnSorter(dataTable, rowCount, columnIdentifier, direction, supportMultiSort);
 316                case Serializable.SerializableTypes.Int:
 0317                    return new IntColumnSorter(dataTable, rowCount, columnIdentifier, direction, supportMultiSort);
 318                case Serializable.SerializableTypes.String:
 0319                    return new StringColumnSorter(dataTable, rowCount, columnIdentifier, direction, supportMultiSort);
 320                case Serializable.SerializableTypes.Bool:
 0321                    return new BoolColumnSorter(dataTable, rowCount, columnIdentifier, direction, supportMultiSort);
 322                case Serializable.SerializableTypes.Double:
 0323                    return new DoubleColumnSorter(dataTable, rowCount, columnIdentifier, direction, supportMultiSort);
 324                case Serializable.SerializableTypes.Long:
 0325                    return new LongColumnSorter(dataTable, rowCount, columnIdentifier, direction, supportMultiSort);
 326                case Serializable.SerializableTypes.ULong:
 0327                    return new ULongColumnSorter(dataTable, rowCount, columnIdentifier, direction, supportMultiSort);
 328                case Serializable.SerializableTypes.UInt:
 0329                    return new UIntColumnSorter(dataTable, rowCount, columnIdentifier, direction, supportMultiSort);
 330                case Serializable.SerializableTypes.EnumInt:
 0331                    return new EnumIntColumnSorter(dataTable, rowCount, columnIdentifier, direction, supportMultiSort);
 332            }
 333
 0334            Debug.LogError($"Unable to find sorter for requested column type [{type.GetLabel()}].");
 0335            return null;
 0336        }
 337#endif
 338    }
 339}