Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Difference between "fixed" and "native" types

Discussion in 'Entity Component System' started by JakHussain, Jun 10, 2020.

  1. JakHussain

    JakHussain

    Joined:
    Oct 20, 2016
    Posts:
    318
    I'm having trouble understanding what the difference is between the fixed and native types found in the collections package. Both FixedListFloat32 and NativeList<int> both implement INativeList<int> and are both structs so it looks like both can be passed into jobs no problem. The fixed collections all say they're of a fixed size but there's add an remove methods in them so is is that they are of a fixed capacity? What's the usecase for a fixed collection over a native one?

    I would ask the same for the string collections as well. The Burst documentation states that Debug.Log is supported in burst so long as you use string literals and FixedString types as arguments in your job. But then what's a NativeString used for?

    I've never seen anyone talk about these fixed types before so it's really thrown me off on what I should be doing and made me feel like I understand a lot less than i thought it did o_O
     
  2. Zuntatos

    Zuntatos

    Joined:
    Nov 18, 2012
    Posts:
    612
    At least with regard to the FixedList variants, I believe those to be "pointer-free lists"; the entire collection in stored directly in the struct. While a NativeList<> has a pointer to explicitly allocated memory. I haven't tested this but presumably this means you can have a NativeArray<FixedListFloat32> where a NativeArray<NativeArray<float>> isn't supported.
     
  3. JooleanLogic

    JooleanLogic

    Joined:
    Mar 1, 2018
    Posts:
    447
    Yeah they're fixed capacity and Add() will throw if you go past it.
    I didn't realise there was a FixedListFloat32. I've been using FixedList32<float>

    I assume the main use case of them is that we can add strings and arrays to entity components. You can't add NativeList to a component.

    I actually wasn't aware of FixedString either and have been using NativeString. They appear structurally identical and I'd be interested to know what the difference is also.
     
  4. JakHussain

    JakHussain

    Joined:
    Oct 20, 2016
    Posts:
    318
    Final question, though this may seem dumb, what do the numbers at the end of the fixed type names signify? My assumption would be that the capacity of the collection would be N for a FixedListN. Does this also carry over to FixedStringN where N is the max capacity of characters?
     
  5. JakHussain

    JakHussain

    Joined:
    Oct 20, 2016
    Posts:
    318
    My best guess is that the NativeString is mainly for parallel reading and writing in jobs whereas passing a FixedString into a job would be equivalent to passing a plain int to a job which results in each thread getting a copy of a FixedString rather than referring to the same NativeString since as @Zuntatos explained, the native types actually point to a location in memory.

    I guess native types work basically like pseudo reference types while fixed types function exactly like a struct with non of the parallel safety magic of the job system because that stuff doesn't apply.
     
  6. JooleanLogic

    JooleanLogic

    Joined:
    Mar 1, 2018
    Posts:
    447
    No, it's the size in bytes minus two bytes to store the length. It's not number of elements.
    Code (CSharp):
    1. public struct FixedString32 {
    2.     internal ushort utf8LengthInBytes;
    3.     internal FixedBytes30 bytes;
    4. }
    Same for FixedList
    No NativeString is just like FixedString. They're not the same as NativeList/NativeArray though which is what you might be thinking of.
    Code (CSharp):
    1. public struct NativeString32 {
    2.     public ushort LengthInBytes;
    3.     public Bytes30 buffer;
    4. }
     
    JakHussain likes this.
  7. AnthonyReddan

    AnthonyReddan

    Joined:
    Feb 27, 2018
    Posts:
    39
    So we should be using FixedString types instead of Native if I understand this correctly?:

    From https://docs.unity3d.com/Packages/com.unity.collections@0.6/changelog/CHANGELOG.html
     
  8. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,993
    Yes.
     
    AnthonyReddan likes this.
  9. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    948
    The Fixed* types can be used inside component structs like if you need a container with limited contents.
     
  10. AnthonyReddan

    AnthonyReddan

    Joined:
    Feb 27, 2018
    Posts:
    39
    Is it possible to allocate for a list of strings on the heap? In C++ I'd do something like..:

    Code (CSharp):
    1. char** array = new char*[HUGE_SIZE];
    2. for(int i = 0; i < HUGE_SIZE; ++i)
    3. {
    4.     array = new char[32];
    5. }
    Maybe like this..?:

    Code (CSharp):
    1. NativeArray<char> array = new NativeArray<char>(HUGE_SIZE * 32, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
    Possibly using byte instead of char?

    Asking because of this line specifically in the
    FixedString
    documentation:
     
  11. burningmime

    burningmime

    Joined:
    Jan 25, 2014
    Posts:
    845
    If all your strings are exactly 32 bytes long, then what's wrong with
    NativeArray<FixedString32> array = new NativeArray<FixedString32>(HUGE_SIZE, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
    ? Or, if you don't need to use them in jobs,
    FixedString32[] array = new FixedString32[HUGE_SIZE]
    .

    If they're variable size and you don't need to use them in jobs, then
    string[] array = new string[HUGE_SIZE]
    . If they're variable-size and you do need to use them in jobs, then you need to store the data and offsets separately or otherwise come up with your own way of storing them.

    char
    is 16 bits (2 bytes) to store UCS-16. If you only need ASCII characters or can convert back and forth from UTF-8, then
    byte
    , but it's not particularly convenient to use it as a string type. Can I ask what your use case is?
     
    AnthonyReddan likes this.
  12. AnthonyReddan

    AnthonyReddan

    Joined:
    Feb 27, 2018
    Posts:
    39
    Hey @burningmime thanks thats exactly what I wanted to hear! I guess theres nothing wrong with that (and seems in fact, exactly what I want). I just had concerns maybe FixedStringN were specifically stack allocated and maybe it wouldn't even allow me to allocate a NativeArray using that type? Was just based on the wording here:

    Code (CSharp):
    1. Those who need more than 65,535 contiguous items should allocate from the heap, as storing that many things contiguously in a C# struct is likely to result in much wasted time, as the compiler copies the struct often.
    My exact use case is that I'm making a word game so its a lot of string processing but only at edit time. I'm packing all the data up into a Tree which I store as a flat array of uint (each uint represents a node and is packed with various flags, the byte char, and an offset to the next node). I do all this at edit time but I was still wanting to use jobs to make the processing time faster (right now its taking up to 30 seconds using regular C# and I wanted to make it faster ;P).