lib/standard/bytes: Added pop method
[nit.git] / lib / standard / bytes.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Services for byte streams and arrays
16 module bytes
17
18 import kernel
19 import collection::array
20 intrude import text::flat
21
22 # A buffer containing Byte-manipulation facilities
23 #
24 # Uses Copy-On-Write when persisted
25 class Bytes
26 super AbstractArray[Byte]
27
28 # A NativeString being a char*, it can be used as underlying representation here.
29 private var items: NativeString
30
31 # Number of bytes in the array
32 redef var length
33
34 # Capacity of the array
35 private var capacity: Int
36
37 # Has this buffer been persisted (to_s'd)?
38 #
39 # Used for Copy-On-Write
40 private var persisted = false
41
42 # var b = new Bytes.empty
43 # assert b.to_s == ""
44 init empty do
45 var ns = new NativeString(0)
46 init(ns, 0, 0)
47 end
48
49 init with_capacity(cap: Int) do
50 var ns = new NativeString(cap)
51 init(ns, 0, cap)
52 end
53
54 redef fun is_empty do return length != 0
55
56 # var b = new Bytes.empty
57 # b.add 101u8
58 # assert b[0] == 101u8
59 redef fun [](i) do
60 assert i >= 0
61 assert i < length
62 return items[i]
63 end
64
65 # var b = new Bytes.with_capacity(1)
66 # b[0] = 101u8
67 # assert b.to_s == "e"
68 redef fun []=(i, v) do
69 if persisted then regen
70 assert i >= 0
71 assert i <= length
72 if i == length then add(v)
73 items[i] = v
74 end
75
76 # var b = new Bytes.empty
77 # b.add 101u8
78 # assert b.to_s == "e"
79 redef fun add(c) do
80 if persisted then regen
81 if length >= capacity then
82 enlarge(length)
83 end
84 items[length] = c
85 length += 1
86 end
87
88 # var b = new Bytes.empty
89 # b.append([104u8, 101u8, 108u8, 108u8, 111u8])
90 # assert b.to_s == "hello"
91 redef fun append(arr) do
92 if arr isa Bytes then
93 append_ns(arr.items, arr.length)
94 else
95 for i in arr do add i
96 end
97 end
98
99 # var b = new Bytes.empty
100 # b.append([0x41u8, 0x41u8, 0x18u8])
101 # b.pop
102 # assert b.to_s == "AA"
103 redef fun pop do
104 assert length >= 1
105 length -= 1
106 return items[length]
107 end
108
109 redef fun clear do length = 0
110
111 # Regenerates the buffer, necessary when it was persisted
112 private fun regen do
113 var nns = new NativeString(capacity)
114 items.copy_to(nns, length, 0, 0)
115 persisted = false
116 end
117
118 # Appends the `ln` first bytes of `ns` to self
119 fun append_ns(ns: NativeString, ln: Int) do
120 if persisted then regen
121 var nlen = length + ln
122 if nlen > capacity then enlarge(nlen)
123 ns.copy_to(items, ln, 0, length)
124 length += ln
125 end
126
127 # Appends `ln` bytes from `ns` starting at index `from` to self
128 fun append_ns_from(ns: NativeString, ln, from: Int) do
129 if persisted then regen
130 var nlen = length + ln
131 if nlen > capacity then enlarge(nlen)
132 ns.copy_to(items, ln, from, length)
133 length += ln
134 end
135
136 redef fun enlarge(sz) do
137 if capacity >= sz then return
138 persisted = false
139 while capacity < sz do capacity = capacity * 2 + 2
140 var ns = new NativeString(capacity)
141 items.copy_to(ns, length, 0, 0)
142 items = ns
143 end
144
145 redef fun to_s do
146 persisted = true
147 return new FlatString.with_infos(items, length, 0, length -1)
148 end
149
150 redef fun iterator do return new BytesIterator.with_buffer(self)
151 end
152
153 private class BytesIterator
154 super IndexedIterator[Byte]
155
156 var tgt: NativeString
157
158 redef var index
159
160 var max: Int
161
162 init with_buffer(b: Bytes) do init(b.items, 0, b.length - 1)
163
164 redef fun is_ok do return index < max
165
166 redef fun next do index += 1
167
168 redef fun item do return tgt[index]
169 end
170
171 redef class NativeString
172 fun to_bytes: Bytes do
173 var len = cstring_length
174 return new Bytes(self, len, len)
175 end
176 end