diff options
Diffstat (limited to 'erts/emulator/beam/elib_memmove.c')
-rw-r--r-- | erts/emulator/beam/elib_memmove.c | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/erts/emulator/beam/elib_memmove.c b/erts/emulator/beam/elib_memmove.c new file mode 100644 index 0000000000..d2fe8649ed --- /dev/null +++ b/erts/emulator/beam/elib_memmove.c @@ -0,0 +1,113 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* + * This memmove assumes that both src and dst are aligned on an address + * divisible by 4 and that n is a multiple of four. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifndef HAVE_MEMMOVE + +#define MEMCPY_LIMIT 12 +typedef unsigned long u_long; +typedef unsigned short u_short; + +static void copy_high(dst, src, n) +char* dst; char* src; int n; +{ + dst += n; + src += n; + + if (n >= MEMCPY_LIMIT) { + while(((u_long) dst) & 3) { + *--dst = *--src; + n--; + } + if ((((u_long) src) & 3) == 0) { + while(n >= sizeof(u_long)) { + src -= sizeof(u_long); + dst -= sizeof(u_long); + *((u_long*)dst) = *((u_long*)src); + n -= sizeof(u_long); + } + } + else if ((((u_short) src) & 3) == 2) { + while(n >= sizeof(u_short)) { + src -= sizeof(u_short); + dst -= sizeof(u_short); + *((u_short*)dst) = *((u_short*)src); + n -= sizeof(u_short); + } + } + } + while(n > 0) { + *--dst = *--src; + n--; + } +} + +static void copy_low(dst, src, n) +char* dst; char* src; int n; +{ + if (n >= MEMCPY_LIMIT) { + while(((u_long) dst) & 3) { + *dst++ = *src++; + n--; + } + if ((((u_long) src) & 3) == 0) { + while(n >= sizeof(u_long)) { + *((u_long*)dst) = *((u_long*)src); + src += sizeof(u_long); + dst += sizeof(u_long); + n -= sizeof(u_long); + } + } + else if ((((u_long) src) & 3) == 2) { + while(n >= sizeof(u_short)) { + *((u_short*)dst) = *((u_short*)src); + src += sizeof(u_short); + dst += sizeof(u_short); + n -= sizeof(u_short); + } + } + } + while(n > 0) { + *dst++ = *src++; + n--; + } +} + +/* +** Move memory (with overlap) +*/ +void* memmove(dst, src, n) +char* dst; char* src; int n; +{ + if (dst < src) + copy_low(dst, src, n); + else if (dst > src) + copy_high(dst, src, n); + return dst; +} + +#endif /* HAVE_MEMMOVE */ |