Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
张重言
deno
提交
957050cd
D
deno
项目概览
张重言
/
deno
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
deno
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
未验证
提交
957050cd
编写于
4月 17, 2020
作者:
C
Chris Knight
提交者:
GitHub
4月 17, 2020
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feature: synchronous buffered writer (#4693)
上级
41f836dc
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
207 addition
and
58 deletion
+207
-58
std/io/bufio.ts
std/io/bufio.ts
+160
-52
std/io/bufio_test.ts
std/io/bufio_test.ts
+35
-0
std/io/util.ts
std/io/util.ts
+12
-6
未找到文件。
std/io/bufio.ts
浏览文件 @
957050cd
...
...
@@ -5,6 +5,7 @@
type
Reader
=
Deno
.
Reader
;
type
Writer
=
Deno
.
Writer
;
type
SyncWriter
=
Deno
.
SyncWriter
;
import
{
charCode
,
copyBytes
}
from
"
./util.ts
"
;
import
{
assert
}
from
"
../testing/asserts.ts
"
;
...
...
@@ -400,6 +401,40 @@ export class BufReader implements Reader {
}
}
abstract
class
AbstractBufBase
{
buf
!
:
Uint8Array
;
usedBufferBytes
=
0
;
err
:
Error
|
null
=
null
;
/** Size returns the size of the underlying buffer in bytes. */
size
():
number
{
return
this
.
buf
.
byteLength
;
}
/** Returns how many bytes are unused in the buffer. */
available
():
number
{
return
this
.
buf
.
byteLength
-
this
.
usedBufferBytes
;
}
/** buffered returns the number of bytes that have been written into the
* current buffer.
*/
buffered
():
number
{
return
this
.
usedBufferBytes
;
}
checkBytesWritten
(
numBytesWritten
:
number
):
void
{
if
(
numBytesWritten
<
this
.
usedBufferBytes
)
{
if
(
numBytesWritten
>
0
)
{
this
.
buf
.
copyWithin
(
0
,
numBytesWritten
,
this
.
usedBufferBytes
);
this
.
usedBufferBytes
-=
numBytesWritten
;
}
this
.
err
=
new
Error
(
"
Short write
"
);
throw
this
.
err
;
}
}
}
/** BufWriter implements buffering for an deno.Writer object.
* If an error occurs writing to a Writer, no more data will be
* accepted and all subsequent writes, and flush(), will return the error.
...
...
@@ -407,106 +442,179 @@ export class BufReader implements Reader {
* flush() method to guarantee all data has been forwarded to
* the underlying deno.Writer.
*/
export
class
BufWriter
implements
Writer
{
buf
:
Uint8Array
;
n
=
0
;
err
:
Error
|
null
=
null
;
/** return new BufWriter unless w is BufWriter */
static
create
(
w
:
Writer
,
size
:
number
=
DEFAULT_BUF_SIZE
):
BufWriter
{
return
w
instanceof
BufWriter
?
w
:
new
BufWriter
(
w
,
size
);
export
class
BufWriter
extends
AbstractBufBase
implements
Writer
{
/** return new BufWriter unless writer is BufWriter */
static
create
(
writer
:
Writer
,
size
:
number
=
DEFAULT_BUF_SIZE
):
BufWriter
{
return
writer
instanceof
BufWriter
?
writer
:
new
BufWriter
(
writer
,
size
);
}
constructor
(
private
wr
:
Writer
,
size
:
number
=
DEFAULT_BUF_SIZE
)
{
constructor
(
private
writer
:
Writer
,
size
:
number
=
DEFAULT_BUF_SIZE
)
{
super
();
if
(
size
<=
0
)
{
size
=
DEFAULT_BUF_SIZE
;
}
this
.
buf
=
new
Uint8Array
(
size
);
}
/** Size returns the size of the underlying buffer in bytes. */
size
():
number
{
return
this
.
buf
.
byteLength
;
}
/** Discards any unflushed buffered data, clears any error, and
* resets b to write its output to w.
* resets b
uffer
to write its output to w.
*/
reset
(
w
:
Writer
):
void
{
this
.
err
=
null
;
this
.
n
=
0
;
this
.
wr
=
w
;
this
.
usedBufferBytes
=
0
;
this
.
wr
iter
=
w
;
}
/** Flush writes any buffered data to the underlying io.Writer. */
async
flush
():
Promise
<
void
>
{
if
(
this
.
err
!==
null
)
throw
this
.
err
;
if
(
this
.
n
===
0
)
return
;
if
(
this
.
usedBufferBytes
===
0
)
return
;
let
n
=
0
;
let
n
umBytesWritten
=
0
;
try
{
n
=
await
this
.
wr
.
write
(
this
.
buf
.
subarray
(
0
,
this
.
n
));
numBytesWritten
=
await
this
.
writer
.
write
(
this
.
buf
.
subarray
(
0
,
this
.
usedBufferBytes
)
);
}
catch
(
e
)
{
this
.
err
=
e
;
throw
e
;
}
if
(
n
<
this
.
n
)
{
if
(
n
>
0
)
{
this
.
buf
.
copyWithin
(
0
,
n
,
this
.
n
);
this
.
n
-=
n
;
this
.
checkBytesWritten
(
numBytesWritten
);
this
.
usedBufferBytes
=
0
;
}
/** Writes the contents of `data` into the buffer. If the contents won't fully
* fit into the buffer, those bytes that can are copied into the buffer, the
* buffer is the flushed to the writer and the remaining bytes are copied into
* the now empty buffer.
*
* @return the number of bytes written to the buffer.
*/
async
write
(
data
:
Uint8Array
):
Promise
<
number
>
{
if
(
this
.
err
!==
null
)
throw
this
.
err
;
if
(
data
.
length
===
0
)
return
0
;
let
totalBytesWritten
=
0
;
let
numBytesWritten
=
0
;
while
(
data
.
byteLength
>
this
.
available
())
{
if
(
this
.
buffered
()
===
0
)
{
// Large write, empty buffer.
// Write directly from data to avoid copy.
try
{
numBytesWritten
=
await
this
.
writer
.
write
(
data
);
}
catch
(
e
)
{
this
.
err
=
e
;
throw
e
;
}
}
else
{
numBytesWritten
=
copyBytes
(
this
.
buf
,
data
,
this
.
usedBufferBytes
);
this
.
usedBufferBytes
+=
numBytesWritten
;
await
this
.
flush
();
}
t
his
.
err
=
new
Error
(
"
Short write
"
)
;
throw
this
.
err
;
t
otalBytesWritten
+=
numBytesWritten
;
data
=
data
.
subarray
(
numBytesWritten
)
;
}
this
.
n
=
0
;
numBytesWritten
=
copyBytes
(
this
.
buf
,
data
,
this
.
usedBufferBytes
);
this
.
usedBufferBytes
+=
numBytesWritten
;
totalBytesWritten
+=
numBytesWritten
;
return
totalBytesWritten
;
}
}
/** Returns how many bytes are unused in the buffer. */
available
():
number
{
return
this
.
buf
.
byteLength
-
this
.
n
;
/** BufWriterSync implements buffering for a deno.SyncWriter object.
* If an error occurs writing to a SyncWriter, no more data will be
* accepted and all subsequent writes, and flush(), will return the error.
* After all data has been written, the client should call the
* flush() method to guarantee all data has been forwarded to
* the underlying deno.SyncWriter.
*/
export
class
BufWriterSync
extends
AbstractBufBase
implements
SyncWriter
{
/** return new BufWriterSync unless writer is BufWriterSync */
static
create
(
writer
:
SyncWriter
,
size
:
number
=
DEFAULT_BUF_SIZE
):
BufWriterSync
{
return
writer
instanceof
BufWriterSync
?
writer
:
new
BufWriterSync
(
writer
,
size
);
}
/** buffered returns the number of bytes that have been written into the
* current buffer.
constructor
(
private
writer
:
SyncWriter
,
size
:
number
=
DEFAULT_BUF_SIZE
)
{
super
();
if
(
size
<=
0
)
{
size
=
DEFAULT_BUF_SIZE
;
}
this
.
buf
=
new
Uint8Array
(
size
);
}
/** Discards any unflushed buffered data, clears any error, and
* resets buffer to write its output to w.
*/
buffered
():
number
{
return
this
.
n
;
reset
(
w
:
SyncWriter
):
void
{
this
.
err
=
null
;
this
.
usedBufferBytes
=
0
;
this
.
writer
=
w
;
}
/** Flush writes any buffered data to the underlying io.SyncWriter. */
flush
():
void
{
if
(
this
.
err
!==
null
)
throw
this
.
err
;
if
(
this
.
usedBufferBytes
===
0
)
return
;
let
numBytesWritten
=
0
;
try
{
numBytesWritten
=
this
.
writer
.
writeSync
(
this
.
buf
.
subarray
(
0
,
this
.
usedBufferBytes
)
);
}
catch
(
e
)
{
this
.
err
=
e
;
throw
e
;
}
this
.
checkBytesWritten
(
numBytesWritten
);
this
.
usedBufferBytes
=
0
;
}
/** Writes the contents of p into the buffer.
* Returns the number of bytes written.
/** Writes the contents of `data` into the buffer. If the contents won't fully
* fit into the buffer, those bytes that can are copied into the buffer, the
* buffer is the flushed to the writer and the remaining bytes are copied into
* the now empty buffer.
*
* @return the number of bytes written to the buffer.
*/
async
write
(
p
:
Uint8Array
):
Promise
<
number
>
{
writeSync
(
data
:
Uint8Array
):
number
{
if
(
this
.
err
!==
null
)
throw
this
.
err
;
if
(
p
.
length
===
0
)
return
0
;
if
(
data
.
length
===
0
)
return
0
;
let
n
n
=
0
;
let
n
=
0
;
while
(
p
.
byteLength
>
this
.
available
())
{
let
totalBytesWritte
n
=
0
;
let
n
umBytesWritten
=
0
;
while
(
data
.
byteLength
>
this
.
available
())
{
if
(
this
.
buffered
()
===
0
)
{
// Large write, empty buffer.
// Write directly from
p
to avoid copy.
// Write directly from
data
to avoid copy.
try
{
n
=
await
this
.
wr
.
write
(
p
);
n
umBytesWritten
=
this
.
writer
.
writeSync
(
data
);
}
catch
(
e
)
{
this
.
err
=
e
;
throw
e
;
}
}
else
{
n
=
copyBytes
(
this
.
buf
,
p
,
this
.
n
);
this
.
n
+=
n
;
await
this
.
flush
();
n
umBytesWritten
=
copyBytes
(
this
.
buf
,
data
,
this
.
usedBufferBytes
);
this
.
usedBufferBytes
+=
numBytesWritte
n
;
this
.
flush
();
}
nn
+=
n
;
p
=
p
.
subarray
(
n
);
totalBytesWritten
+=
numBytesWritte
n
;
data
=
data
.
subarray
(
numBytesWritte
n
);
}
n
=
copyBytes
(
this
.
buf
,
p
,
this
.
n
);
this
.
n
+=
n
;
nn
+=
n
;
return
n
n
;
n
umBytesWritten
=
copyBytes
(
this
.
buf
,
data
,
this
.
usedBufferBytes
);
this
.
usedBufferBytes
+=
numBytesWritte
n
;
totalBytesWritten
+=
numBytesWritte
n
;
return
totalBytesWritte
n
;
}
}
...
...
std/io/bufio_test.ts
浏览文件 @
957050cd
...
...
@@ -14,6 +14,7 @@ import {
import
{
BufReader
,
BufWriter
,
BufWriterSync
,
BufferFullError
,
PartialReadError
,
readStringDelim
,
...
...
@@ -353,6 +354,40 @@ Deno.test(async function bufioWriter(): Promise<void> {
}
});
Deno
.
test
(
function
bufioWriterSync
():
void
{
const
data
=
new
Uint8Array
(
8192
);
for
(
let
i
=
0
;
i
<
data
.
byteLength
;
i
++
)
{
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
data
[
i
]
=
charCode
(
"
"
)
+
(
i
%
(
charCode
(
"
~
"
)
-
charCode
(
"
"
)));
}
const
w
=
new
Buffer
();
for
(
const
nwrite
of
bufsizes
)
{
for
(
const
bs
of
bufsizes
)
{
// Write nwrite bytes using buffer size bs.
// Check that the right amount makes it out
// and that the data is correct.
w
.
reset
();
const
buf
=
new
BufWriterSync
(
w
,
bs
);
const
context
=
`nwrite=
${
nwrite
}
bufsize=
${
bs
}
`
;
const
n
=
buf
.
writeSync
(
data
.
subarray
(
0
,
nwrite
));
assertEquals
(
n
,
nwrite
,
context
);
buf
.
flush
();
const
written
=
w
.
bytes
();
assertEquals
(
written
.
byteLength
,
nwrite
);
for
(
let
l
=
0
;
l
<
written
.
byteLength
;
l
++
)
{
assertEquals
(
written
[
l
],
data
[
l
]);
}
}
}
});
Deno
.
test
(
async
function
bufReaderReadFull
():
Promise
<
void
>
{
const
enc
=
new
TextEncoder
();
const
dec
=
new
TextDecoder
();
...
...
std/io/util.ts
浏览文件 @
957050cd
...
...
@@ -5,14 +5,20 @@ type Reader = Deno.Reader;
import
*
as
path
from
"
../path/mod.ts
"
;
import
{
encode
}
from
"
../encoding/utf8.ts
"
;
// `off` is the offset into `dst` where it will at which to begin writing values
// from `src`.
// Returns the number of bytes copied.
/**
* Copy bytes from one Uint8Array to another. Bytes from `src` which don't fit
* into `dst` will not be copied.
*
* @param dst Destination byte array
* @param src Source byte array
* @param off Offset into `dst` at which to begin writing values from `src`.
* @return number of bytes copied
*/
export
function
copyBytes
(
dst
:
Uint8Array
,
src
:
Uint8Array
,
off
=
0
):
number
{
off
=
Math
.
max
(
0
,
Math
.
min
(
off
,
dst
.
byteLength
));
const
r
=
dst
.
byteLength
-
off
;
if
(
src
.
byteLength
>
r
)
{
src
=
src
.
subarray
(
0
,
r
);
const
dstBytesAvailable
=
dst
.
byteLength
-
off
;
if
(
src
.
byteLength
>
dstBytesAvailable
)
{
src
=
src
.
subarray
(
0
,
dstBytesAvailable
);
}
dst
.
set
(
src
,
off
);
return
src
.
byteLength
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录