aboutsummaryrefslogtreecommitdiffstats
path: root/jrt/src/com/yahoo/jrt/Buffer.java
blob: 48a9de28c2800fa1c96b0cf52e2444d17dcf0c4f (plain) (blame)
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.jrt;


import java.nio.ByteBuffer;


class Buffer {
    private ByteBuffer buf;
    private int        readPos;
    private int        writePos;
    private boolean    readMode;

    private void setReadMode() {
        if (readMode) {
            buf.limit(writePos);
            return;
        }
        writePos = buf.position();
        buf.position(readPos);
        buf.limit(writePos);
        readMode = true;
    }

    private void setWriteMode() {
        if (!readMode) {
            buf.limit(buf.capacity());
            return;
        }
        readPos = buf.position();
        buf.limit(buf.capacity());
        if (readPos == writePos) {
            readPos = 0;
            writePos = 0;
        }
        buf.position(writePos);
        readMode = false;
    }

    private void ensureFree(int minFree) {
        // assumes setWriteMode called just before
        if (buf.remaining() >= minFree) {
            return;
        }
        writePos = buf.position();
        int used = writePos - readPos;
        int free = buf.remaining() + readPos;
        if (free >= minFree && free >= used) {
            buf.position(readPos);
            buf.limit(writePos);
            buf.compact();
            readPos = 0;
        } else {
            int size = buf.capacity() * 2;
            if (buf.capacity() + free < minFree) {
                size = buf.capacity() + minFree;
            }
            ByteBuffer tmp = ByteBuffer.allocate(size);
            tmp.order(buf.order());
            buf.position(readPos);
            buf.limit(writePos);
            tmp.put(buf);
            buf = tmp;
            readPos = 0;
        }
    }

    public Buffer(int size) {
        buf = ByteBuffer.allocate(size);
        readPos = 0;
        writePos = 0;
        readMode = false;
    }

    public boolean shrink(int size) {
        int rpos = readMode? buf.position() : readPos;
        int wpos = readMode? writePos : buf.position();
        int used = wpos - rpos;
        if (used > size || buf.capacity() <= size) {
            return false;
        }
        ByteBuffer tmp = ByteBuffer.allocate(size);
        tmp.order(buf.order());
        buf.position(rpos);
        buf.limit(wpos);
        tmp.put(buf);
        buf = tmp;
        readPos = 0;
        writePos = used;
        buf.position(readMode? readPos : writePos);
        buf.limit(readMode? writePos : buf.capacity());
        return true;
    }

    public int bytes() {
        return (readMode)
            ? (writePos - buf.position())
            : (buf.position() - readPos);
    }

    public ByteBuffer getReadable() {
        setReadMode();
        return buf;
    }

    public ByteBuffer getWritable(int minFree) {
        setWriteMode();
        ensureFree(minFree);
        return buf;
    }
}