/*
	mem_cpy(dst, src, n)

	Copy bytes from source to destination areas, while properly handling
	areas that overlap.
	
	mem_cpy attempts to copy sizeof(MAXCOPYTYPE) bytes at a time.

	mem_cpy optimizes copies in more situations than 4.3 BSD UNIX bcopy().

	On a Sun SPARCstation/1, mem_cpy is twice as fast as bcopy,
	presumably because it copies chunks of data that are twice as big
	(and it can do so with more byte-alignment combinations).

	W. Gish, December 1989
*/
#include <ncbi.h>
#include <gishlib.h>

void _cdecl
mem_cpy(d, s, n)
	Nlm_VoidPtr	d, s;
	register size_t	n;
{
	register CharPtr	dst = d, src = s;
	register size_t	saven;
#ifdef MAXCOPYTYPE
	register MAXCOPYTYPE	PNTR ms, PNTR md;
	register long		PNTR ls, PNTR ld;
#endif

	if (dst > src) {	/* Copy from end to start */
		src += n;
		dst += n;
#ifdef MAXCOPYTYPE
		/* See if part of the copy can be done with MAXCOPYTYPE words */
		if (n >= 2*sizeof(MAXCOPYTYPE) &&
				((int)src&(sizeof(MAXCOPYTYPE)-1)) == 
				((int)dst&(sizeof(MAXCOPYTYPE)-1)) ) {
			/* Get pointers aligned on a MAXCOPYTYPE boundary */
			if ( ((int)src & (sizeof(MAXCOPYTYPE)-1)) != 0)
				do {
					*--dst = *--src, --n;
				} while ((int)src & (sizeof(MAXCOPYTYPE)-1));
			saven = n;
			n /= sizeof(MAXCOPYTYPE);
			saven -= (n * sizeof(MAXCOPYTYPE));
			ms = (MAXCOPYTYPE *)src, md = (MAXCOPYTYPE *)dst;
			do *--md = *--ms; while (--n);
			/* Finish up by copying individual bytes */
			src = (CharPtr)ms, dst = (CharPtr)md;
			while (saven-- > 0) *--dst = *--src;
		}
		else
			if (n >= 2*sizeof(long) &&
					((int)src&(sizeof(long)-1)) == 
					((int)dst&(sizeof(long)-1)) ) {
				/* Get pointers aligned on a long word boundary */
				if ( ((int)src & (sizeof(long)-1)) != 0)
					do
						*--dst = *--src, --n;
					while ((int)src & (sizeof(long)-1));
				saven = n;
				n /= sizeof(long);
				saven -= (n * sizeof(long));
				ls = (long PNTR)src, ld = (long PNTR)dst;
				do *--ld = *--ls; while (--n);
				/* Finish up by copying individual bytes */
				src = (CharPtr)ls, dst = (CharPtr)ld;
				while (saven-- > 0) *--dst = *--src;
			}
			else
#endif /* MAXCOPYTYPE */
				while (n-- > 0) *--dst = *--src;
		return;
	}
	if (dst < src) {	/* Copy from start to end */
#ifdef MAXCOPYTYPE
		/* See if part of the copy can be done with MAXCOPYTYPE words */
		if (n >= 2*sizeof(MAXCOPYTYPE) &&
				((int)src&(sizeof(MAXCOPYTYPE)-1)) == 
				((int)dst&(sizeof(MAXCOPYTYPE)-1)) ) {
			/* Get pointers aligned to a common word boundary */
			while ((int)src & (sizeof(MAXCOPYTYPE)-1))
				*dst++ = *src++, --n;
			saven = n;
			n /= sizeof(MAXCOPYTYPE);
			saven -= (n * sizeof(MAXCOPYTYPE));
			ms = (MAXCOPYTYPE *)src, md = (MAXCOPYTYPE *)dst;
			do *md++ = *ms++; while (--n);
			/* Finish up by copying individual bytes */
			src = (CharPtr)ms, dst = (CharPtr)md;
			while (saven-- > 0) *dst++ = *src++;
		}
		else
			if (n >= 2*sizeof(long) &&
					((int)src&(sizeof(long)-1)) == 
					((int)dst&(sizeof(long)-1)) ) {
				/* Get pointers aligned to a common word boundary */
				while ((int)src & (sizeof(long)-1))
					*dst++ = *src++, --n;
				saven = n;
				n /= sizeof(long);
				saven -= n * sizeof(long);
				ls = (long PNTR)src, ld = (long PNTR)dst;
				do *ld++ = *ls++; while (--n);
				/* Finish up by copying individual bytes */
				src = (CharPtr)ls, dst = (CharPtr)ld;
				while (saven-- > 0) *dst++ = *src++;
			}
			else
#endif /* MAXCOPYTYPE */
				while (n-- > 0) *dst++ = *src++;
	}
}
