{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/coreclr/issues/1015","labels_url":"https://api.github.com/repos/dotnet/coreclr/issues/1015/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/coreclr/issues/1015/comments","events_url":"https://api.github.com/repos/dotnet/coreclr/issues/1015/events","html_url":"https://github.com/dotnet/coreclr/issues/1015","id":77751220,"number":1015,"title":"Provide API for Primitive / Struct Array \"Views\"","user":{"login":"AdamsLair","id":5013908,"avatar_url":"https://avatars.githubusercontent.com/u/5013908?v=3","gravatar_id":"","url":"https://api.github.com/users/AdamsLair","html_url":"https://github.com/AdamsLair","followers_url":"https://api.github.com/users/AdamsLair/followers","following_url":"https://api.github.com/users/AdamsLair/following{/other_user}","gists_url":"https://api.github.com/users/AdamsLair/gists{/gist_id}","starred_url":"https://api.github.com/users/AdamsLair/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AdamsLair/subscriptions","organizations_url":"https://api.github.com/users/AdamsLair/orgs","repos_url":"https://api.github.com/users/AdamsLair/repos","events_url":"https://api.github.com/users/AdamsLair/events{/privacy}","received_events_url":"https://api.github.com/users/AdamsLair/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":16,"created_at":"2015-05-18T18:16:55Z","updated_at":"2015-05-29T17:21:57Z","closed_at":null,"body":"## Problem Description\r\n\r\nConsider the following case:\r\n\r\n```\r\n[StructLayout(StructLayout.Sequential)]\r\nstruct ColorRgba { byte R; byte G; byte B; byte A; }\r\n\r\nprivate void Foo(byte[] colorDataRgba)\r\n{\r\n    // To interface with a library or other code, I need my color data in a different format.\r\n    ColorRgba[] colorsA = ???;\r\n    int[] colorsB = ???;\r\n}\r\n```\r\n\r\nThere are two ways of getting the color data in a different format:\r\n\r\n1. Creating a new array of the appropriate size and do a block copy on it. This will result in a big performance hit for large arrays. Think of a 2048x2048 image in RGBA format. Might take \"a while\".\r\n2. Using unsafe code to obtain a pointer to the array, cast it and then use that for access. This is essentially \"free\".\r\n\r\nSo, while the second approach may be preferable for high-performance code, it is not viable when passing array data to a class instance that requires a different format and at the same time wants to take ownership of that data - because it can't store a fixed unsafe pointer permanently. Thus, copying is the only choice here.\r\n\r\n[There is a hack](http://stackoverflow.com/a/3577227/2015377) to be able to \"cast\" the array into the desired format, but that has its own problems and looks like it's going to break as soon as some core data layout changes, or the code is ported to a different platform. Generally not the kind of code you'd want in a C# project.\r\n\r\n## A Bad Idea\r\n\r\nAllowing all arrays of structs and primitive types to be cast is probably not a good idea.\r\n\r\n- It will make a very niche and questionable operation more accessible and inviting.\r\n- There will be the problem of the arrays element length, which will need to be recalculated when the element type size changes.\r\n  - The recalculation itself may be questionable when the numbers don't add up. What will happen when casting a byte[] into a ColorRgba[] (4 bytes each) when the byte array was only two elements long? Could throw an exception when performing the cast.\r\n  - What will happen to other references to that same array, which are not cast? Their Length property would \"magically\" change into a wrong value. Definitely **not** viable.\r\n  - Alternatively, an arrays length value could be internally expressed in bytes and be calculated upon access, depending on the type of the array. However, this would likely have a performance impact in various spots. Probably not viable either.\r\n\r\n## A Hopefully Better Idea\r\n\r\nAs a different approach, maybe it would be possible to introduce \"view\" arrays that essentially wrap another existing arrays data segment and specify a new element type:\r\n\r\n```\r\nprivate void Foo(byte[] colorDataRgba)\r\n{\r\n    // Create a new \"view\" array that internally points to the data \r\n    // block of the original array. Could also do safety checks.\r\n    ColorRgba[] colors = Array.CreateView<ColorRgba>(colorDataRgba);\r\n    \r\n    // Properly recalculated to colorDataRgba.Length / 4 and \r\n    // stored permanently in the view array header for performance reasons.\r\n    Console.WriteLine(colors.Length);\r\n    \r\n    // Accesses the same data directly, without copying or casting\r\n    Console.WriteLine(colors[0]);\r\n}\r\n```\r\n\r\nNot sure about the internal additions that would be required for this, but I'd imagine the existing array header layout should have enough space to store a flag for being a view array and a pointer towards the actual data block.\r\n\r\n## Proposed Solution\r\n\r\nTo me, the \"view\" array idea sounds most reasonable, but I'm sure others will have a far better grasp on this. \r\n\r\nWhat do you think?"},"comment":{"url":"https://api.github.com/repos/dotnet/coreclr/issues/comments/106876986","html_url":"https://github.com/dotnet/coreclr/issues/1015#issuecomment-106876986","issue_url":"https://api.github.com/repos/dotnet/coreclr/issues/1015","id":106876986,"user":{"login":"omariom","id":1781701,"avatar_url":"https://avatars.githubusercontent.com/u/1781701?v=3","gravatar_id":"","url":"https://api.github.com/users/omariom","html_url":"https://github.com/omariom","followers_url":"https://api.github.com/users/omariom/followers","following_url":"https://api.github.com/users/omariom/following{/other_user}","gists_url":"https://api.github.com/users/omariom/gists{/gist_id}","starred_url":"https://api.github.com/users/omariom/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/omariom/subscriptions","organizations_url":"https://api.github.com/users/omariom/orgs","repos_url":"https://api.github.com/users/omariom/repos","events_url":"https://api.github.com/users/omariom/events{/privacy}","received_events_url":"https://api.github.com/users/omariom/received_events","type":"User","site_admin":false},"created_at":"2015-05-29T17:21:56Z","updated_at":"2015-05-29T17:21:56Z","body":"The benefit would be that the source byte array won't be pinned in memory.\r\n\r\n```C#\r\nvar messageView = new ByteArrayView<Message>(bytes, numberOfElements);\r\nlong id = messageView[0].Id;\r\nProcessMessage(ref messageView[0]);\r\n```\r\n\r\nGeneric argument must not contain pointers (references) directly or indirectly.\r\nConstructor of ByteArrayView throws if  sizeof(Message) * numberOfElements doesn't fit into bytes.\r\nThe indexer behaves like array's indexer, e.g. throws IndexOutOfRangeException .\r\n\r\nAlso I'd like ByteArrayView to be immutable struct. This way we wouldn't have to pay the cost of  allocation of it.\r\n\r\n\r\n"}}