aboutsummaryrefslogtreecommitdiffstats
path: root/lib/swap16.cpp
blob: f20efc0deae5b7c41ea7d0ea2b52ee7fba66985c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/* Copyright 2012 Dietrich Epp <depp@zdome.net> */
#include "convert.h"
#include <cstdint>

void lfr_swap16(void *dest, const void *src, size_t count)
{
    size_t i, n;
    unsigned x, y;
    const unsigned char *s8;
    unsigned char *d8;
    const unsigned short *s16;
    unsigned short *d16;
    const unsigned *s32;
    unsigned *d32;

    if (!count)
        return;

    if ((((uintptr_t) dest | (uintptr_t) src) & 1u) != 0) {
        /* completely unaligned */
        s8 = reinterpret_cast<const unsigned char*>(src);
        d8 = reinterpret_cast<unsigned char*>(dest);
        for (i = 0; i < count; ++i) {
            x = s8[i*2+0];
            y = s8[i*2+1];
            d8[i*2+0] = static_cast<unsigned char>(y);
            d8[i*2+1] = static_cast<unsigned char>(x);
        }
    } else if ((((uintptr_t) dest - (uintptr_t) src) & 3u) != 0) {
        /* 16-bit aligned */
        s16 = reinterpret_cast<const unsigned short*>(src);
        d16 = reinterpret_cast<unsigned short*>(dest);;
        for (i = 0; i < count; ++i) {
            x = s16[i];
            d16[i] = static_cast<unsigned short>((x >> 8) | (x << 8));
        }
    } else {
        /* 16-bit aligned, with 32-bit aligned delta */
        s16 = reinterpret_cast<const unsigned short*>(src);
        d16 = reinterpret_cast<unsigned short*>(dest);
        n = count;
        if ((uintptr_t) dest & 3u) {
            x = s16[0];
            d16[0] = static_cast<unsigned short>((x >> 8) | (x << 8));
            n -= 1;
            s16 += 1;
            d16 += 1;
        }
        s32 = reinterpret_cast<const unsigned*>(s16);
        d32 = reinterpret_cast<unsigned*>(d16);
        for (i = 0; i < n/2; ++i) {
            x = s32[i];
            d32[i] = ((x >> 8) & 0xff00ffu) | ((x & 0xff00ffu) << 8);
        }
        d32 += n/2;
        s32 += n/2;
        n -= (n/2)*2;
        if (n) {
            s16 = reinterpret_cast<const unsigned short*>(s32);
            d16 = reinterpret_cast<unsigned short*>(d32);
            x = s16[0];
            d16[0] = static_cast<unsigned short>((x >> 8) | (x << 8));
        }
    }
}