MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4// ReSharper disable UnusedMember.Global5 6using System.Collections.Generic;7using System.Globalization;8using System.Management.Automation.Internal;9using System.Management.Automation.Runspaces;10 11namespace System.Management.Automation12{13 internal static class ArrayOps14 {15 internal static object AddObjectArray(object[] lhs, object rhs)16 {17 int newIdx = lhs.Length;18 Array.Resize(ref lhs, newIdx + 1);19 lhs[newIdx] = rhs;20 21 return lhs;22 }23 24 internal static object[] SlicingIndex(object target, object[] indexes, Func<object, object, object> indexer)25 {26 var result = new object[indexes.Length];27 int j = 0;28 foreach (object t in indexes)29 {30 var value = indexer(target, t);31 if (value != AutomationNull.Value)32 {33 result[j++] = value;34 }35 }36 37 if (j != indexes.Length)38 {39 var shortResult = new object[j];40 Array.Copy(result, shortResult, j);41 return shortResult;42 }43 44 return result;45 }46 47 /// <summary>48 /// Efficiently multiplies collection by integer.49 /// </summary>50 /// <param name="array">Collection to multiply.</param>51 /// <param name="times">Number of times the collection is to be multiplied/copied.</param>52 /// <returns>Collection multiplied by integer.</returns>53 internal static T[] Multiply<T>(T[] array, uint times)54 {55 Diagnostics.Assert(array != null, "Caller should verify the arguments for array multiplication");56 57 if (times == 1)58 {59 return array;60 }61 62 if (times == 0 || array.Length == 0)63 {64#pragma warning disable CA1825 // Avoid zero-length array allocations65 // Don't use Array.Empty<T>(); always return a new instance.66 return new T[0];67#pragma warning restore CA1825 // Avoid zero-length array allocations68 }69 70 var context = LocalPipeline.GetExecutionContextFromTLS();71 if (context != null &&72 context.LanguageMode == PSLanguageMode.RestrictedLanguage && (array.Length * times) > 1024)73 {74 throw InterpreterError.NewInterpreterException(times, typeof(RuntimeException),75 null, "ArrayMultiplyToolongInDataSection", ParserStrings.ArrayMultiplyToolongInDataSection, 1024);76 }77 78 var uncheckedLength = array.Length * times;79 int elements = -1;80 try81 {82 elements = checked((int)uncheckedLength);83 }84 catch (OverflowException)85 {86 LanguagePrimitives.ThrowInvalidCastException(uncheckedLength, typeof(int));87 }88 89 // Make the minimum number of calls to Array.Copy by doubling the array up to90 // the most significant bit in times, then do one final Array.Copy to get the91 // remaining copies.92 93 T[] result = new T[elements];94 int resultLength = array.Length;95 Array.Copy(array, 0, result, 0, resultLength);96 times >>= 1;97 while (times != 0)98 {99 Array.Copy(result, 0, result, resultLength, resultLength);100 resultLength *= 2;101 times >>= 1;102 }103 104 if (result.Length != resultLength)105 {106 Array.Copy(result, 0, result, resultLength, (result.Length - resultLength));107 }108 109 return result;110 }111 112 internal static object GetMDArrayValue(Array array, int[] indexes, bool slicing)113 {114 if (array.Rank != indexes.Length)115 {116 ReportIndexingError(array, indexes, null);117 }118 119 for (int i = 0; i < indexes.Length; ++i)120 {121 int ub = array.GetUpperBound(i);122 int lb = array.GetLowerBound(i);123 if (indexes[i] < lb)124 {125 indexes[i] = indexes[i] + ub + 1;126 }127 128 if (indexes[i] < lb || indexes[i] > ub)129 {130 // In strict mode, don't return, fall through and let Array.GetValue raise an exception.131 var context = LocalPipeline.GetExecutionContextFromTLS();132 if (context != null && !context.IsStrictVersion(3))133 {134 // If we're slicing, return AutomationNull.Value to signal no result)135 return slicing ? AutomationNull.Value : null;136 }137 }138 }139 140 // All indexes have been validated, so this won't raise an exception.141 return array.GetValue(indexes);142 }143 144 internal static object GetMDArrayValueOrSlice(Array array, object indexes)145 {146 Exception whyFailed = null;147 int[] indexArray = null;148 try149 {150 indexArray = (int[])LanguagePrimitives.ConvertTo(indexes, typeof(int[]), NumberFormatInfo.InvariantInfo);151 }152 catch (InvalidCastException ice)153 {154 // Ignore an exception here as we may actually be looking at an array of arrays155 // which could still be ok. Save the exception as we may use it later...156 whyFailed = ice;157 }158 159 if (indexArray != null)160 {161 if (indexArray.Length != array.Rank)162 {163 // rank failed to match so error...164 ReportIndexingError(array, indexes, null);165 }166 167 return GetMDArrayValue(array, indexArray, false);168 }169 170 var indexList = new List<int[]>();171 172 var ie = LanguagePrimitives.GetEnumerator(indexes);173 while (EnumerableOps.MoveNext(null, ie))174 {175 var currentIndex = EnumerableOps.Current(ie);176 try177 {178 indexArray = LanguagePrimitives.ConvertTo<int[]>(currentIndex);179 }180 catch (InvalidCastException)181 {182 indexArray = null;183 }184 185 if (indexArray == null || indexArray.Length != array.Rank)186 {187 if (whyFailed != null)188 {189 // If the first fails, report the original exception and all indices190 ReportIndexingError(array, indexes, whyFailed);191 Diagnostics.Assert(false, "ReportIndexingError must throw");192 }193 // If the second or subsequent index fails, report the failure for just that index194 ReportIndexingError(array, currentIndex, null);195 Diagnostics.Assert(false, "ReportIndexingError must throw");196 }197 198 // Only use whyFailed the first time through, otherwise199 whyFailed = null;200 indexList.Add(indexArray);201 }202 203 // Optimistically assume all indices are valid so the result array is the same size.204 // If that turns out to be wrong, we'll just copy the elements produced.205 var result = new object[indexList.Count];206 int j = 0;207 foreach (var i in indexList)208 {209 var value = GetMDArrayValue(array, i, true);210 if (value != AutomationNull.Value)211 {212 result[j++] = value;213 }214 }215 216 if (j != indexList.Count)217 {218 var shortResult = new object[j];219 Array.Copy(result, shortResult, j);220 return shortResult;221 }222 223 return result;224 }225 226 private static void ReportIndexingError(Array array, object index, Exception reason)227 {228 // Convert this index into something printable (we hope)...229 string msgString = IndexStringMessage(index);230 231 if (reason == null)232 {233 throw InterpreterError.NewInterpreterException(index, typeof(RuntimeException), null,234 "NeedMultidimensionalIndex", ParserStrings.NeedMultidimensionalIndex, array.Rank, msgString);235 }236 237 throw InterpreterError.NewInterpreterExceptionWithInnerException(index, typeof(RuntimeException), null,238 "NeedMultidimensionalIndex", ParserStrings.NeedMultidimensionalIndex, reason, array.Rank, msgString);239 }240 241 internal static string IndexStringMessage(object index)242 {243 // Convert this index into something printable (we hope)...244 string msgString = PSObject.ToString(null, index, ",", null, null, true, true);245 if (msgString.Length > 20)246 msgString = string.Concat(msgString.AsSpan(0, 20), " ...");247 return msgString;248 }249 250 internal static object SetMDArrayValue(Array array, int[] indexes, object value)251 {252 if (array.Rank != indexes.Length)253 {254 ReportIndexingError(array, indexes, null);255 }256 257 for (int i = 0; i < indexes.Length; ++i)258 {259 int ub = array.GetUpperBound(i);260 int lb = array.GetLowerBound(i);261 if (indexes[i] < lb)262 {263 indexes[i] = indexes[i] + ub + 1;264 }265 }266 267 array.SetValue(value, indexes);268 return value;269 }270 271 internal static object GetNonIndexable(object target, object[] indices)272 {273 // We want to allow:274 // $x[0]275 // and276 // $x[-1]277 // to be the same as278 // $x279 // But disallow anything else:280 // if in the strict mode, throw exception281 // otherwise, return AutomationNull.Value to signal no result282 283 if (indices.Length == 1)284 {285 var index = indices[0];286 if (index != null && (LanguagePrimitives.Equals(0, index) || LanguagePrimitives.Equals(-1, index)))287 {288 return target;289 }290 }291 292 var context = LocalPipeline.GetExecutionContextFromTLS();293 if (context == null || !context.IsStrictVersion(2))294 {295 return AutomationNull.Value;296 }297 298 throw InterpreterError.NewInterpreterException(target, typeof(RuntimeException), null, "CannotIndex",299 ParserStrings.CannotIndex, target.GetType());300 }301 }302}303 