Difference between revisions of "Reference:Array"

From POV-Wiki
Jump to navigation Jump to search
m (broken line repair)
m (Precision about 40 char limited version number)
 
(11 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{#indexentry:Identifiers, array|Array, identifiers}}
+
{{#indexentry:Identifiers, array}}
 +
{{#indexentry:Array, identifiers}}
 +
{{#indexentry:array, dictionary}}
 +
{{#indexentry:dictionary, array}}
 +
{{#indexentry:array, mixed}}
 +
{{#indexentry:mixed, array}}
 
{{#indexentry:array}}
 
{{#indexentry:array}}
<p>You may declare arrays of identifiers of up to five dimensions. Any
+
{{#indexentry:keyword, global, dictionary}}
item that can be declared as an identifier can be declared in an array.</p>
+
{{#indexentry:keyword, local, dictionary}}
 +
{{#indexentry:global, dictionary}}
 +
{{#indexentry:local, dictionary}}
 +
<p>You may declare arrays of identifiers with up to five dimensions. Any item that can be declared as an identifier can be declared in an array. Consequential to the improvements with the classic <code>array</code> container topology, two {{New}} features in version 3.8 extended functionality to allow the creation of <code>dictionary</code> container types. Additionally arrays now support a mixed-type declaration. Dictionaries can be used for mapping string keys to arbitrary-type values. The mixed-type declaration allows the array to hold elements of different types.</p>
  
{{#indexentry:Array, declaring|Declaring, arrays}}
 
 
==Declaring Arrays==
 
==Declaring Arrays==
<p>The syntax for declaring an array is as follows:</p>
+
{{#indexentry:Array, declaring}}
 +
{{#indexentry:Declaring, arrays}}
 +
<p>The syntax is as follows:</p>
 +
 
 
<pre>
 
<pre>
 
ARRAY_DECLARATION:
 
ARRAY_DECLARATION:
   #declare IDENTIFIER = array[ INT ][[ INT ]]..[ARRAY_INITIALIZER] |
+
   #declare IDENTIFIER = array [mixed] [[ INT ]]..[ARRAY_INITIALIZER] |
   #local IDENTIFIER = array[ INT ][[ INT ]]..[ARRAY_INITIALIZER]
+
   #local IDENTIFIER = array [mixed] [[ INT ]]..[ARRAY_INITIALIZER]
 
ARRAY_INITIALIZER:
 
ARRAY_INITIALIZER:
 
   {ARRAY_ITEM, [ARRAY_ITEM, ]... }
 
   {ARRAY_ITEM, [ARRAY_ITEM, ]... }
 
ARRAY_ITEM:
 
ARRAY_ITEM:
 
   RVALUE | ARRAY_INITIALIZER
 
   RVALUE | ARRAY_INITIALIZER
 +
DICTIONARY_DECLARATION:
 +
  #declare IDENTIFIER = dictionary; | #local IDENTIFIER = dictionary;
 +
  #declare IDENTIFIER = dictionary DICTIONARY_INITIALIZER |
 +
  #local IDENTIFIER = dictionary DICTIONARY_INITIALIZER
 +
DICTIONARY_INITIALIZER:
 +
  {DICTIONARY_ITEM, [DICTIONARY_ITEM, ]... }
 +
DICTIONARY_ITEM:
 +
  [ STRING ] : DICTIONARY_ENTRY | .STRING_IDENTIFIER: DICTIONARY_ENTRY
 +
DICTIONARY_ENTRY:
 +
  Any valid array entry
 
</pre>
 
</pre>
  
<p>Where IDENTIFIER is the name of the identifier up to 40 characters long
+
<p>Where IDENTIFIER is the name of the identifier and INT is a valid float expression, internally truncated to an integer, and used to specify the size of the array.</p>
and INT is a valid float expression which is internally truncated to an
+
 
integer which specifies the size of the array. The optional <em>
+
<p class="Note"><strong>Note:</strong> In versions prior to 3.6.2, IDENTIFIER names <em>were</em> limited to 40 characters. There has been a {{Change}} removing that restriction.</p>
ARRAY_INITIALIZER</em> is discussed in the next section <!--<linkto "Array Initializers">Array Initializers</linkto>--->[[Reference:Array#Array Initializers|Array Initializers]].
+
 
Here is an example of a one-dimensional, uninitialized array.</p>
+
<p>See [[Reference:Array#Array Initializers|Array Initializers]] for more about the optional <em>ARRAY_INITIALIZER</em> parameter.</p>
 +
 
 +
<p>Consider the following example of a one-dimensional, uninitialized array:</p>
 +
 
 
<pre>
 
<pre>
 
#declare MyArray = array[10]
 
#declare MyArray = array[10]
 
</pre>
 
</pre>
  
<p>This declares an uninitialized array of ten elements. The elements are
+
<p>It declares an uninitialized array of ten elements. The elements are referenced as <code>MyArray[0]</code> through <code>MyArray[9]</code>. As yet, the type of the elements are undetermined. Once you have initialized any element of the array, all other elements can only be defined as that type. {{New}} in version 3.8 this behavior can be over-ridden by using the <code>mixed</code> keyword in the array declaration allowing mixed-type elements. Irregardless of whether the array elements have mixed-types or not, any attempt to reference an uninitialized element results in an error. More below:</p>
referenced as <code>MyArray[0]</code> through <code>MyArray[9]</code>. As
+
 
yet, the type of the elements are undetermined. Once you have initialized any
 
element of the array, all other elements can only be defined as that type. An
 
attempt to reference an uninitialized element results in an error. For
 
example:</p>
 
 
<pre>
 
<pre>
 
#declare MyArray = array[10]
 
#declare MyArray = array[10]
Line 38: Line 57:
 
#declare MyArray[2] = normal{bumps 0.2}  //generates an error
 
#declare MyArray[2] = normal{bumps 0.2}  //generates an error
 
#declare Thing = MyArray[4]              //error: uninitialized array element
 
#declare Thing = MyArray[4]              //error: uninitialized array element
 +
 +
// mixed-type array declaration
 +
#declare Foo = array mixed[3];
 +
#declare Foo[0] = 42;
 +
#declare Foo[1] = "Fnord";
 +
#declare Foo[2] = sphere { <0,0,0>, 1 }
 
</pre>
 
</pre>
  
<p>Multi-dimensional arrays up to five dimensions may be declared. For
+
<p>Multi-dimensional arrays up to five dimensions may be declared. This example ... </p>
example:</p>
+
 
 
<pre>
 
<pre>
 
#declare MyGrid = array[4][5]
 
#declare MyGrid = array[4][5]
 
</pre>
 
</pre>
  
<p>declares a 20 element array of 4 rows and 5 columns. Elements are
+
<p>... declares a 20 element array of 4 rows and 5 columns. Elements are referenced from <code>MyGrid[0][0]</code> to <code>MyGrid[3][4]</code>. Although it is permissible to reference an entire array as a whole, you may not reference just one dimension of a multi-dimensional array.</p>
referenced from <code>MyGrid[0][0]</code> to <code>MyGrid[3][4]</code>.
+
 
Although it is permissible to reference an entire array as a whole, you may
 
not reference just one dimension of a multi-dimensional array. For
 
example:</p>
 
 
<pre>
 
<pre>
 
#declare MyArray = array[10]
 
#declare MyArray = array[10]
Line 58: Line 80:
 
#declare OneRow  = MyGrid[2]  //this is illegal
 
#declare OneRow  = MyGrid[2]  //this is illegal
 
</pre>
 
</pre>
<p>The <code>[[Reference:Conditional Directives#The ifdef and ifndef Directives|:#ifdef|#ifdef]]</code> and <code>[[Reference:Conditional Directives#The ifdef and ifndef Directives|:#ifndef|#ifndef]]</code> directives can be used to check whether a specific element of an array has been declared. For methods to determine the size of an array look in the float section for <code>[[Reference:Numeric_Expressions#Functions|:dimensions|dimensions]]</code> and
 
<code>[[Reference:Numeric_Expressions#Functions|:dimension_size|dimension_size]]</code>.</p>
 
  
<p>Large uninitialized arrays do not take much memory. Internally they are
+
<p>The <code>[[Reference:Conditional Directives#The ifdef and ifndef Directives|#ifdef]]</code> and <code>[[Reference:Conditional Directives#The ifdef and ifndef Directives|#ifndef]]</code> directives can be used to check whether a specific element of an array has been declared. See also: <code>[[Reference:Numeric Expressions#Functions|dimensions]]</code> and <code>[[Reference:Numeric Expressions#Functions|dimension_size]]</code> for additional information about the methods used to determine the size of arrays.</p>
arrays of pointers so they probably use just 4 bytes per element. Once
+
 
initialized with values, they consume memory depending on what you put in
+
<p>Large uninitialized arrays do not take much memory. Internally they are arrays of pointers so they probably use just 8 bytes per element. Once initialized with values, they consume memory depending on what they contain.</p>
them.</p>
+
 
<p>
+
<p>The rules for <em>local</em> vs <em>global</em> arrays are the same as any other identifier.</p>
The rules for local vs. global arrays are the same as any other identifier.</p>
+
 
 
<p class="Note"><strong>Note:</strong> This applies to the entire array. You cannot mix local and global
 
<p class="Note"><strong>Note:</strong> This applies to the entire array. You cannot mix local and global
elements in the same array. See <!--<linkto "#declare vs. #local">#declare vs. #local</linkto>--->[[Reference:Declare and Local Directives#declare vs. local|#declare vs. #local]] for
+
elements in the same array. See <!--<linkto "#declare vs. #local">#declare vs. #local</linkto>--->[[Reference:Declare and Local Directives#declare vs. local|#declare vs. #local]] for information on identifier scope.</p>
information on identifier scope.</p>
+
 
 
<p>Any legitimate use of the <code>#declare</code> directive can also be put into an array. In other words, you can also create multidimensional arrays by making an array of arrays.</p>
 
<p>Any legitimate use of the <code>#declare</code> directive can also be put into an array. In other words, you can also create multidimensional arrays by making an array of arrays.</p>
  
{{#indexentry:Array, initialization|Initialization, arrays}}
+
<p>{{New}} to version 3.8 points to also consider:</p>
 +
<ul>
 +
  <li>Array elements no longer have to be all of the same type. However, be aware that mixing elements of different types will increase memory consumption. That increased memory footprint will not revert even if the array is later set to elements all of the same type.</li>
 +
  <li>An array can be declared without specifying any dimensions; in this case the array will be one-dimensional and be able to grow in size dynamically.</li>
 +
  <li>Accessing an element beyond the nominal size of such an array will automatically increase the nominal size just enough to include that element.</li>
 +
  <li>The memory footprint may be <em>twice</em> as high than required for the current nominal size.</li>
 +
  <li>Growth of such an array is triggered by <em>any</em> access to an element beyond the nominal size, this includes tests such as <code>#ifdef(ARRAY[INDEX])</code>.</li>
 +
  <li>The following applies to <code>dictionary</code> containers <em>only</em>:</li>
 +
    <ul>
 +
      <li>When using <em>square bracket notation</em> the keys do not necessarily have to be string literals, they can also be arbitrary string expressions.</li>
 +
      <li>If using <em>dot notation</em> the indices must follow the generic rules for identifiers.</li>
 +
      <li>Included are the two <em>pseudo-dictionaries</em> <code>local</code> and <code>global</code> they represent the <em>most local</em> and the <em>least local</em> or global identifiers respectively.</li>
 +
    </ul>
 +
</ul>
 +
 
 +
<p>Additional usage examples are as follows:</p>
 +
 
 +
<pre>
 +
// create an empty dictionary
 +
#declare Fnord = dictionary;
 +
 
 +
// create a dictionary with elements
 +
#declare Fnord = dictionary {
 +
  ["Foo"]: 42,
 +
  ["Bar"]: sphere { <0,0,0>, 1 }
 +
}
 +
 
 +
// alternative
 +
#declare Fnord = dictionary {
 +
  .Foo: 42,
 +
  .Bar: sphere { <0,0,0>, 1 }
 +
}
 +
 
 +
// access a dictionary element
 +
#declare Fnord["Foo"] = 42;
 +
#declare Answer = Fnord["Foo"];
 +
 
 +
// alternative
 +
#declare Fnord.Foo = 42;
 +
#declare Answer = Fnord.Foo;
 +
 
 +
// test whether a dictionary contains a particular key
 +
#ifdef (Fnord["Foo"]) ... #end
 +
#declare FooKeyExists = defined(Fnord.Foo);
 +
 
 +
// remove a key from a dictionary
 +
#undef Fnord["Foo"]
 +
 
 +
// declare a local and un-define any global variable of same name
 +
#declare local.Foo = 4711;
 +
#undef global.Foo
 +
</pre>
 +
 
 
==Array Initializers==
 
==Array Initializers==
<p>Because it is cumbersome to individually initialize the elements of an
+
{{#indexentry:Array, initialization}}
array, you may initialize it as it is created using array initializer syntax.
+
{{#indexentry:Initialization, arrays}}
For example:</p>
+
<p>Because it can be cumbersome to individually initialize the elements of an array, you may initialize it as it is created using <code>array</code> initializer syntax.</p>
 
<pre>
 
<pre>
 
#include &quot;colors.inc&quot;
 
#include &quot;colors.inc&quot;
Line 82: Line 154:
 
</pre>
 
</pre>
  
<p>Multi-dimensional arrays may also be initialized this way. For
+
<p>Multi-dimensional arrays may also be initialized this way.</p>
example:</p>
 
 
<pre>
 
<pre>
 
#declare Digits =
 
#declare Digits =
Line 94: Line 165:
 
</pre>
 
</pre>
  
<p>The commas are required between elements and between dimensions as shown
+
<p>The commas are required between elements and between dimensions as shown in the example.</p>
in the example.</p>
 

Latest revision as of 20:49, 2 July 2021

You may declare arrays of identifiers with up to five dimensions. Any item that can be declared as an identifier can be declared in an array. Consequential to the improvements with the classic array container topology, two New features in version 3.8 extended functionality to allow the creation of dictionary container types. Additionally arrays now support a mixed-type declaration. Dictionaries can be used for mapping string keys to arbitrary-type values. The mixed-type declaration allows the array to hold elements of different types.

Declaring Arrays

The syntax is as follows:

ARRAY_DECLARATION:
  #declare IDENTIFIER = array [mixed] [[ INT ]]..[ARRAY_INITIALIZER] |
  #local IDENTIFIER = array [mixed] [[ INT ]]..[ARRAY_INITIALIZER]
ARRAY_INITIALIZER:
  {ARRAY_ITEM, [ARRAY_ITEM, ]... }
ARRAY_ITEM:
  RVALUE | ARRAY_INITIALIZER
DICTIONARY_DECLARATION:
  #declare IDENTIFIER = dictionary; | #local IDENTIFIER = dictionary;
  #declare IDENTIFIER = dictionary DICTIONARY_INITIALIZER |
  #local IDENTIFIER = dictionary DICTIONARY_INITIALIZER
DICTIONARY_INITIALIZER:
  {DICTIONARY_ITEM, [DICTIONARY_ITEM, ]... }
DICTIONARY_ITEM:
  [ STRING ] : DICTIONARY_ENTRY | .STRING_IDENTIFIER: DICTIONARY_ENTRY
DICTIONARY_ENTRY:
  Any valid array entry

Where IDENTIFIER is the name of the identifier and INT is a valid float expression, internally truncated to an integer, and used to specify the size of the array.

Note: In versions prior to 3.6.2, IDENTIFIER names were limited to 40 characters. There has been a Change removing that restriction.

See Array Initializers for more about the optional ARRAY_INITIALIZER parameter.

Consider the following example of a one-dimensional, uninitialized array:

#declare MyArray = array[10]

It declares an uninitialized array of ten elements. The elements are referenced as MyArray[0] through MyArray[9]. As yet, the type of the elements are undetermined. Once you have initialized any element of the array, all other elements can only be defined as that type. New in version 3.8 this behavior can be over-ridden by using the mixed keyword in the array declaration allowing mixed-type elements. Irregardless of whether the array elements have mixed-types or not, any attempt to reference an uninitialized element results in an error. More below:

#declare MyArray = array[10]
#declare MyArray[5] = pigment{White}     //all other elements must 
                                         //be pigments too.
#declare MyArray[2] = normal{bumps 0.2}  //generates an error
#declare Thing = MyArray[4]              //error: uninitialized array element

// mixed-type array declaration
#declare Foo = array mixed[3];
#declare Foo[0] = 42;
#declare Foo[1] = "Fnord";
#declare Foo[2] = sphere { <0,0,0>, 1 }

Multi-dimensional arrays up to five dimensions may be declared. This example ...

#declare MyGrid = array[4][5]

... declares a 20 element array of 4 rows and 5 columns. Elements are referenced from MyGrid[0][0] to MyGrid[3][4]. Although it is permissible to reference an entire array as a whole, you may not reference just one dimension of a multi-dimensional array.

#declare MyArray = array[10]
#declare MyGrid = array[4][5]
#declare YourArray = MyArray  //this is ok
#declare YourGrid = MyGrid    //so is this
#declare OneRow  = MyGrid[2]  //this is illegal

The #ifdef and #ifndef directives can be used to check whether a specific element of an array has been declared. See also: dimensions and dimension_size for additional information about the methods used to determine the size of arrays.

Large uninitialized arrays do not take much memory. Internally they are arrays of pointers so they probably use just 8 bytes per element. Once initialized with values, they consume memory depending on what they contain.

The rules for local vs global arrays are the same as any other identifier.

Note: This applies to the entire array. You cannot mix local and global elements in the same array. See #declare vs. #local for information on identifier scope.

Any legitimate use of the #declare directive can also be put into an array. In other words, you can also create multidimensional arrays by making an array of arrays.

New to version 3.8 points to also consider:

  • Array elements no longer have to be all of the same type. However, be aware that mixing elements of different types will increase memory consumption. That increased memory footprint will not revert even if the array is later set to elements all of the same type.
  • An array can be declared without specifying any dimensions; in this case the array will be one-dimensional and be able to grow in size dynamically.
  • Accessing an element beyond the nominal size of such an array will automatically increase the nominal size just enough to include that element.
  • The memory footprint may be twice as high than required for the current nominal size.
  • Growth of such an array is triggered by any access to an element beyond the nominal size, this includes tests such as #ifdef(ARRAY[INDEX]).
  • The following applies to dictionary containers only:
    • When using square bracket notation the keys do not necessarily have to be string literals, they can also be arbitrary string expressions.
    • If using dot notation the indices must follow the generic rules for identifiers.
    • Included are the two pseudo-dictionaries local and global they represent the most local and the least local or global identifiers respectively.

Additional usage examples are as follows:

// create an empty dictionary
#declare Fnord = dictionary;

// create a dictionary with elements
#declare Fnord = dictionary {
  ["Foo"]: 42,
  ["Bar"]: sphere { <0,0,0>, 1 }
}

// alternative
#declare Fnord = dictionary {
  .Foo: 42,
  .Bar: sphere { <0,0,0>, 1 }
}

// access a dictionary element
#declare Fnord["Foo"] = 42;
#declare Answer = Fnord["Foo"];

// alternative
#declare Fnord.Foo = 42;
#declare Answer = Fnord.Foo;

// test whether a dictionary contains a particular key
#ifdef (Fnord["Foo"]) ... #end
#declare FooKeyExists = defined(Fnord.Foo);

// remove a key from a dictionary
#undef Fnord["Foo"]

// declare a local and un-define any global variable of same name
#declare local.Foo = 4711;
#undef global.Foo

Array Initializers

Because it can be cumbersome to individually initialize the elements of an array, you may initialize it as it is created using array initializer syntax.

#include "colors.inc"
#declare FlagColors = array[3] {Red,White,Blue}

Multi-dimensional arrays may also be initialized this way.

#declare Digits =
array[4][10] {
  {7,6,7,0,2,1,6,5,5,0},
  {1,2,3,4,5,6,7,8,9,0},
  {0,9,8,7,6,5,4,3,2,1},
  {1,1,2,2,3,3,4,4,5,5}
  }

The commas are required between elements and between dimensions as shown in the example.