Home | History | Annotate | Line # | Download | only in rt
      1 /**
      2  * Implementation of array assignment support routines.
      3  *
      4  *
      5  * Copyright: Copyright Digital Mars 2010 - 2016.
      6  * License:   Distributed under the
      7  *            $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
      8  * Authors:   Walter Bright, Kenji Hara
      9  * Source:    $(DRUNTIMESRC rt/_arrayassign.d)
     10  */
     11 
     12 module rt.arrayassign;
     13 
     14 private
     15 {
     16     import core.internal.util.array;
     17     import core.stdc.string;
     18     import core.stdc.stdlib;
     19     debug(PRINTF) import core.stdc.stdio;
     20 }
     21 
     22 /**
     23  * Keep for backward binary compatibility. This function can be removed in the future.
     24  */
     25 extern (C) void[] _d_arrayassign(TypeInfo ti, void[] from, void[] to)
     26 {
     27     debug(PRINTF) printf("_d_arrayassign(from = %p,%d, to = %p,%d) size = %d\n", from.ptr, from.length, to.ptr, to.length, ti.tsize);
     28 
     29     immutable elementSize = ti.tsize;
     30 
     31     // Need a temporary buffer tmp[] big enough to hold one element
     32     void[16] buf = void;
     33     void* ptmp = (elementSize > buf.sizeof) ? malloc(elementSize) : buf.ptr;
     34     scope (exit)
     35     {
     36         if (ptmp != buf.ptr)
     37             free(ptmp);
     38     }
     39     return _d_arrayassign_l(ti, from, to, ptmp);
     40 }
     41 
     42 /**
     43  * Does array assignment (not construction) from another
     44  * lvalue array of the same element type.
     45  * Handles overlapping copies.
     46  * Input:
     47  *      ti      TypeInfo of the element type.
     48  *      dst     Points target memory. Its .length is equal to the element count, not byte length.
     49  *      src     Points source memory. Its .length is equal to the element count, not byte length.
     50  *      ptmp    Temporary memory for element swapping.
     51  */
     52 extern (C) void[] _d_arrayassign_l(TypeInfo ti, void[] src, void[] dst, void* ptmp)
     53 {
     54     debug(PRINTF) printf("_d_arrayassign_l(src = %p,%d, dst = %p,%d) size = %d\n", src.ptr, src.length, dst.ptr, dst.length, ti.tsize);
     55 
     56     immutable elementSize = ti.tsize;
     57 
     58     enforceRawArraysConformable("copy", elementSize, src, dst, true);
     59 
     60     if (src.ptr < dst.ptr && dst.ptr < src.ptr + elementSize * src.length)
     61     {
     62         // If dst is in the middle of src memory, use reverse order.
     63         for (auto i = dst.length; i--; )
     64         {
     65             void* pdst = dst.ptr + i * elementSize;
     66             void* psrc = src.ptr + i * elementSize;
     67             memcpy(ptmp, pdst, elementSize);
     68             memcpy(pdst, psrc, elementSize);
     69             ti.postblit(pdst);
     70             ti.destroy(ptmp);
     71         }
     72     }
     73     else
     74     {
     75         // Otherwise, use normal order.
     76         foreach (i; 0 .. dst.length)
     77         {
     78             void* pdst = dst.ptr + i * elementSize;
     79             void* psrc = src.ptr + i * elementSize;
     80             memcpy(ptmp, pdst, elementSize);
     81             memcpy(pdst, psrc, elementSize);
     82             ti.postblit(pdst);
     83             ti.destroy(ptmp);
     84         }
     85     }
     86     return dst;
     87 }
     88 
     89 unittest    // Bugzilla 14024
     90 {
     91     string op;
     92 
     93     struct S
     94     {
     95         char x = 'x';
     96         this(this) { op ~= x-0x20; }    // upper case
     97         ~this()    { op ~= x; }         // lower case
     98     }
     99 
    100     S[4] mem;
    101     ref S[2] slice(int a, int b) { return mem[a .. b][0 .. 2]; }
    102 
    103     op = null;
    104     mem[0].x = 'a';
    105     mem[1].x = 'b';
    106     mem[2].x = 'x';
    107     mem[3].x = 'y';
    108     slice(0, 2) = slice(2, 4);  // [ab] = [xy]
    109     assert(op == "XaYb", op);
    110 
    111     op = null;
    112     mem[0].x = 'x';
    113     mem[1].x = 'y';
    114     mem[2].x = 'a';
    115     mem[3].x = 'b';
    116     slice(2, 4) = slice(0, 2);  // [ab] = [xy]
    117     assert(op == "XaYb", op);
    118 
    119     op = null;
    120     mem[0].x = 'a';
    121     mem[1].x = 'b';
    122     mem[2].x = 'c';
    123     slice(0, 2) = slice(1, 3);  // [ab] = [bc]
    124     assert(op == "BaCb", op);
    125 
    126     op = null;
    127     mem[0].x = 'x';
    128     mem[1].x = 'y';
    129     mem[2].x = 'z';
    130     slice(1, 3) = slice(0, 2);  // [yz] = [xy]
    131     assert(op == "YzXy", op);
    132 }
    133 
    134 /**
    135  * Does array assignment (not construction) from another
    136  * rvalue array of the same element type.
    137  * Input:
    138  *      ti      TypeInfo of the element type.
    139  *      dst     Points target memory. Its .length is equal to the element count, not byte length.
    140  *      src     Points source memory. Its .length is equal to the element count, not byte length.
    141  *              It is always allocated on stack and never overlapping with dst.
    142  *      ptmp    Temporary memory for element swapping.
    143  */
    144 extern (C) void[] _d_arrayassign_r(TypeInfo ti, void[] src, void[] dst, void* ptmp)
    145 {
    146     debug(PRINTF) printf("_d_arrayassign_r(src = %p,%d, dst = %p,%d) size = %d\n", src.ptr, src.length, dst.ptr, dst.length, ti.tsize);
    147 
    148     immutable elementSize = ti.tsize;
    149 
    150     enforceRawArraysConformable("copy", elementSize, src, dst, false);
    151 
    152     // Always use normal order, because we can assume that
    153     // the rvalue src has no overlapping with dst.
    154     foreach (i; 0 .. dst.length)
    155     {
    156         void* pdst = dst.ptr + i * elementSize;
    157         void* psrc = src.ptr + i * elementSize;
    158         memcpy(ptmp, pdst, elementSize);
    159         memcpy(pdst, psrc, elementSize);
    160         ti.destroy(ptmp);
    161     }
    162     return dst;
    163 }
    164 
    165 /**
    166  * Does array initialization (not assignment) from another
    167  * array of the same element type.
    168  * ti is the element type.
    169  */
    170 extern (C) void[] _d_arrayctor(TypeInfo ti, void[] from, void[] to)
    171 {
    172     debug(PRINTF) printf("_d_arrayctor(from = %p,%d, to = %p,%d) size = %d\n", from.ptr, from.length, to.ptr, to.length, ti.tsize);
    173 
    174 
    175     auto element_size = ti.tsize;
    176 
    177     enforceRawArraysConformable("initialization", element_size, from, to);
    178 
    179     size_t i;
    180     try
    181     {
    182         for (i = 0; i < to.length; i++)
    183         {
    184             // Copy construction is defined as bit copy followed by postblit.
    185             memcpy(to.ptr + i * element_size, from.ptr + i * element_size, element_size);
    186             ti.postblit(to.ptr + i * element_size);
    187         }
    188     }
    189     catch (Throwable o)
    190     {
    191         /* Destroy, in reverse order, what we've constructed so far
    192          */
    193         while (i--)
    194         {
    195             ti.destroy(to.ptr + i * element_size);
    196         }
    197 
    198         throw o;
    199     }
    200     return to;
    201 }
    202 
    203 
    204 /**
    205  * Do assignment to an array.
    206  *      p[0 .. count] = value;
    207  */
    208 extern (C) void* _d_arraysetassign(void* p, void* value, int count, TypeInfo ti)
    209 {
    210     void* pstart = p;
    211 
    212     auto element_size = ti.tsize;
    213 
    214     // Need a temporary buffer tmp[] big enough to hold one element
    215     immutable maxAllocaSize = 512;
    216     void *ptmp = (element_size > maxAllocaSize) ? malloc(element_size) : alloca(element_size);
    217 
    218     foreach (i; 0 .. count)
    219     {
    220         memcpy(ptmp, p, element_size);
    221         memcpy(p, value, element_size);
    222         ti.postblit(p);
    223         ti.destroy(ptmp);
    224         p += element_size;
    225     }
    226     if (element_size > maxAllocaSize)
    227         free(ptmp);
    228     return pstart;
    229 }
    230 
    231 /**
    232  * Do construction of an array.
    233  *      ti[count] p = value;
    234  */
    235 extern (C) void* _d_arraysetctor(void* p, void* value, int count, TypeInfo ti)
    236 {
    237     void* pstart = p;
    238     auto element_size = ti.tsize;
    239 
    240     try
    241     {
    242         foreach (i; 0 .. count)
    243         {
    244             // Copy construction is defined as bit copy followed by postblit.
    245             memcpy(p, value, element_size);
    246             ti.postblit(p);
    247             p += element_size;
    248         }
    249     }
    250     catch (Throwable o)
    251     {
    252         // Destroy, in reverse order, what we've constructed so far
    253         while (p > pstart)
    254         {
    255             p -= element_size;
    256             ti.destroy(p);
    257         }
    258 
    259         throw o;
    260     }
    261     return pstart;
    262 }
    263