1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package java.nio;
18
19import libcore.io.SizeOf;
20
21/**
22 * This class wraps a byte buffer to be a char buffer.
23 * <p>
24 * Implementation notice:
25 * <ul>
26 * <li>After a byte buffer instance is wrapped, it becomes privately owned by
27 * the adapter. It must NOT be accessed outside the adapter any more.</li>
28 * <li>The byte buffer's position and limit are NOT linked with the adapter.
29 * The adapter extends Buffer, thus has its own position and limit.</li>
30 * </ul>
31 * </p>
32 *
33 */
34final class ByteBufferAsCharBuffer extends CharBuffer {
35
36    private final ByteBuffer byteBuffer;
37
38    static CharBuffer asCharBuffer(ByteBuffer byteBuffer) {
39        ByteBuffer slice = byteBuffer.slice();
40        slice.order(byteBuffer.order());
41        return new ByteBufferAsCharBuffer(slice);
42    }
43
44    private ByteBufferAsCharBuffer(ByteBuffer byteBuffer) {
45        super(byteBuffer.capacity() / SizeOf.CHAR, byteBuffer.effectiveDirectAddress);
46        this.byteBuffer = byteBuffer;
47        this.byteBuffer.clear();
48    }
49
50    @Override
51    public CharBuffer asReadOnlyBuffer() {
52        ByteBufferAsCharBuffer buf = new ByteBufferAsCharBuffer(byteBuffer.asReadOnlyBuffer());
53        buf.limit = limit;
54        buf.position = position;
55        buf.mark = mark;
56        buf.byteBuffer.order = byteBuffer.order;
57        return buf;
58    }
59
60    @Override
61    public CharBuffer compact() {
62        if (byteBuffer.isReadOnly()) {
63            throw new ReadOnlyBufferException();
64        }
65        byteBuffer.limit(limit * SizeOf.CHAR);
66        byteBuffer.position(position * SizeOf.CHAR);
67        byteBuffer.compact();
68        byteBuffer.clear();
69        position = limit - position;
70        limit = capacity;
71        mark = UNSET_MARK;
72        return this;
73    }
74
75    @Override
76    public CharBuffer duplicate() {
77        ByteBuffer bb = byteBuffer.duplicate().order(byteBuffer.order());
78        ByteBufferAsCharBuffer buf = new ByteBufferAsCharBuffer(bb);
79        buf.limit = limit;
80        buf.position = position;
81        buf.mark = mark;
82        return buf;
83    }
84
85    @Override
86    public char get() {
87        if (position == limit) {
88            throw new BufferUnderflowException();
89        }
90        return byteBuffer.getChar(position++ * SizeOf.CHAR);
91    }
92
93    @Override
94    public char get(int index) {
95        checkIndex(index);
96        return byteBuffer.getChar(index * SizeOf.CHAR);
97    }
98
99    @Override
100    public CharBuffer get(char[] dst, int dstOffset, int charCount) {
101        byteBuffer.limit(limit * SizeOf.CHAR);
102        byteBuffer.position(position * SizeOf.CHAR);
103        if (byteBuffer instanceof DirectByteBuffer) {
104            ((DirectByteBuffer) byteBuffer).get(dst, dstOffset, charCount);
105        } else {
106            ((ByteArrayBuffer) byteBuffer).get(dst, dstOffset, charCount);
107        }
108        this.position += charCount;
109        return this;
110    }
111
112    @Override
113    public boolean isDirect() {
114        return byteBuffer.isDirect();
115    }
116
117    @Override
118    public boolean isReadOnly() {
119        return byteBuffer.isReadOnly();
120    }
121
122    @Override
123    public ByteOrder order() {
124        return byteBuffer.order();
125    }
126
127    @Override char[] protectedArray() {
128        throw new UnsupportedOperationException();
129    }
130
131    @Override int protectedArrayOffset() {
132        throw new UnsupportedOperationException();
133    }
134
135    @Override boolean protectedHasArray() {
136        return false;
137    }
138
139    @Override
140    public CharBuffer put(char c) {
141        if (position == limit) {
142            throw new BufferOverflowException();
143        }
144        byteBuffer.putChar(position++ * SizeOf.CHAR, c);
145        return this;
146    }
147
148    @Override
149    public CharBuffer put(int index, char c) {
150        checkIndex(index);
151        byteBuffer.putChar(index * SizeOf.CHAR, c);
152        return this;
153    }
154
155    @Override
156    public CharBuffer put(char[] src, int srcOffset, int charCount) {
157        byteBuffer.limit(limit * SizeOf.CHAR);
158        byteBuffer.position(position * SizeOf.CHAR);
159        if (byteBuffer instanceof DirectByteBuffer) {
160            ((DirectByteBuffer) byteBuffer).put(src, srcOffset, charCount);
161        } else {
162            ((ByteArrayBuffer) byteBuffer).put(src, srcOffset, charCount);
163        }
164        this.position += charCount;
165        return this;
166    }
167
168    @Override
169    public CharBuffer slice() {
170        byteBuffer.limit(limit * SizeOf.CHAR);
171        byteBuffer.position(position * SizeOf.CHAR);
172        ByteBuffer bb = byteBuffer.slice().order(byteBuffer.order());
173        CharBuffer result = new ByteBufferAsCharBuffer(bb);
174        byteBuffer.clear();
175        return result;
176    }
177
178    @Override public CharBuffer subSequence(int start, int end) {
179        checkStartEndRemaining(start, end);
180        CharBuffer result = duplicate();
181        result.limit(position + end);
182        result.position(position + start);
183        return result;
184    }
185}
186