Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
P
protobuf
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
protobuf
Commits
2ee1e523
Commit
2ee1e523
authored
Jul 08, 2016
by
Jon Skeet
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Optimize AddRange for sequences implementing ICollection
(Also fix a few more C# 6-isms.)
parent
b053b921
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
110 additions
and
8 deletions
+110
-8
RepeatedFieldTest.cs
...src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs
+70
-2
RepeatedField.cs
csharp/src/Google.Protobuf/Collections/RepeatedField.cs
+40
-6
No files found.
csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs
View file @
2ee1e523
...
@@ -75,15 +75,83 @@ namespace Google.Protobuf.Collections
...
@@ -75,15 +75,83 @@ namespace Google.Protobuf.Collections
}
}
[
Test
]
[
Test
]
public
void
AddRange
()
public
void
AddRange
_SlowPath
()
{
{
var
list
=
new
RepeatedField
<
string
>();
var
list
=
new
RepeatedField
<
string
>();
list
.
AddRange
(
new
[]
{
"foo"
,
"bar"
});
list
.
AddRange
(
new
[]
{
"foo"
,
"bar"
}
.
Select
(
x
=>
x
)
);
Assert
.
AreEqual
(
2
,
list
.
Count
);
Assert
.
AreEqual
(
2
,
list
.
Count
);
Assert
.
AreEqual
(
"foo"
,
list
[
0
]);
Assert
.
AreEqual
(
"foo"
,
list
[
0
]);
Assert
.
AreEqual
(
"bar"
,
list
[
1
]);
Assert
.
AreEqual
(
"bar"
,
list
[
1
]);
}
}
[
Test
]
public
void
AddRange_SlowPath_NullsProhibited_ReferenceType
()
{
var
list
=
new
RepeatedField
<
string
>();
// It's okay for this to throw ArgumentNullException if necessary.
// It's not ideal, but not awful.
Assert
.
Catch
<
ArgumentException
>(()
=>
list
.
AddRange
(
new
[]
{
"foo"
,
null
}.
Select
(
x
=>
x
)));
}
[
Test
]
public
void
AddRange_SlowPath_NullsProhibited_NullableValueType
()
{
var
list
=
new
RepeatedField
<
int
?>();
// It's okay for this to throw ArgumentNullException if necessary.
// It's not ideal, but not awful.
Assert
.
Catch
<
ArgumentException
>(()
=>
list
.
AddRange
(
new
[]
{
20
,
(
int
?)
null
}.
Select
(
x
=>
x
)));
}
[
Test
]
public
void
AddRange_Optimized_NonNullableValueType
()
{
var
list
=
new
RepeatedField
<
int
>();
list
.
AddRange
(
new
List
<
int
>
{
20
,
30
});
Assert
.
AreEqual
(
2
,
list
.
Count
);
Assert
.
AreEqual
(
20
,
list
[
0
]);
Assert
.
AreEqual
(
30
,
list
[
1
]);
}
[
Test
]
public
void
AddRange_Optimized_ReferenceType
()
{
var
list
=
new
RepeatedField
<
string
>();
list
.
AddRange
(
new
List
<
string
>
{
"foo"
,
"bar"
});
Assert
.
AreEqual
(
2
,
list
.
Count
);
Assert
.
AreEqual
(
"foo"
,
list
[
0
]);
Assert
.
AreEqual
(
"bar"
,
list
[
1
]);
}
[
Test
]
public
void
AddRange_Optimized_NullableValueType
()
{
var
list
=
new
RepeatedField
<
int
?>();
list
.
AddRange
(
new
List
<
int
?>
{
20
,
30
});
Assert
.
AreEqual
(
2
,
list
.
Count
);
Assert
.
AreEqual
((
int
?)
20
,
list
[
0
]);
Assert
.
AreEqual
((
int
?)
30
,
list
[
1
]);
}
[
Test
]
public
void
AddRange_Optimized_NullsProhibited_ReferenceType
()
{
// We don't just trust that a collection with a nullable element type doesn't contain nulls
var
list
=
new
RepeatedField
<
string
>();
// It's okay for this to throw ArgumentNullException if necessary.
// It's not ideal, but not awful.
Assert
.
Catch
<
ArgumentException
>(()
=>
list
.
AddRange
(
new
List
<
string
>
{
"foo"
,
null
}));
}
[
Test
]
public
void
AddRange_Optimized_NullsProhibited_NullableValueType
()
{
// We don't just trust that a collection with a nullable element type doesn't contain nulls
var
list
=
new
RepeatedField
<
int
?>();
// It's okay for this to throw ArgumentNullException if necessary.
// It's not ideal, but not awful.
Assert
.
Catch
<
ArgumentException
>(()
=>
list
.
AddRange
(
new
List
<
int
?>
{
20
,
null
}));
}
[
Test
]
[
Test
]
public
void
Add_RepeatedField
()
public
void
Add_RepeatedField
()
{
{
...
...
csharp/src/Google.Protobuf/Collections/RepeatedField.cs
View file @
2ee1e523
...
@@ -281,12 +281,12 @@ namespace Google.Protobuf.Collections
...
@@ -281,12 +281,12 @@ namespace Google.Protobuf.Collections
/// <summary>
/// <summary>
/// Gets the number of elements contained in the collection.
/// Gets the number of elements contained in the collection.
/// </summary>
/// </summary>
public
int
Count
{
get
{
return
count
;
}
}
public
int
Count
=>
count
;
/// <summary>
/// <summary>
/// Gets a value indicating whether the collection is read-only.
/// Gets a value indicating whether the collection is read-only.
/// </summary>
/// </summary>
public
bool
IsReadOnly
{
get
{
return
false
;
}
}
public
bool
IsReadOnly
=>
false
;
// TODO: Remove this overload and just handle it in the one below, at execution time?
// TODO: Remove this overload and just handle it in the one below, at execution time?
...
@@ -310,7 +310,41 @@ namespace Google.Protobuf.Collections
...
@@ -310,7 +310,41 @@ namespace Google.Protobuf.Collections
public
void
AddRange
(
IEnumerable
<
T
>
values
)
public
void
AddRange
(
IEnumerable
<
T
>
values
)
{
{
ProtoPreconditions
.
CheckNotNull
(
values
,
nameof
(
values
));
ProtoPreconditions
.
CheckNotNull
(
values
,
nameof
(
values
));
// TODO: Check for ICollection and get the Count, to optimize?
// Optimize the case where we know the size and can ask the collection to
// copy itself.
var
collection
=
values
as
ICollection
;
if
(
collection
!=
null
)
{
var
extraCount
=
collection
.
Count
;
// For reference types and nullable value types, we need to check that there are no nulls
// present. (This isn't a thread-safe approach, but we don't advertise this is thread-safe.)
// We expect the JITter to optimize this test to true/false, so it's effectively conditional
// specialization.
if
(
default
(
T
)
==
null
)
{
// TODO: Measure whether iterating once to check and then letting the collection copy
// itself is faster or slower than iterating and adding as we go. For large
// collections this will not be great in terms of cache usage... but the optimized
// copy may be significantly faster than doing it one at a time.
foreach
(
var
item
in
collection
)
{
if
(
item
==
null
)
{
throw
new
ArgumentException
(
"Sequence contained null element"
,
nameof
(
values
));
}
}
}
EnsureSize
(
count
+
extraCount
);
collection
.
CopyTo
(
array
,
count
);
count
+=
extraCount
;
return
;
}
// We *could* check for ICollection<T> as well, but very very few collections implement
// ICollection<T> but not ICollection. (HashSet<T> does, for one...)
// Fall back to a slower path of adding items one at a time.
foreach
(
T
item
in
values
)
foreach
(
T
item
in
values
)
{
{
Add
(
item
);
Add
(
item
);
...
@@ -506,16 +540,16 @@ namespace Google.Protobuf.Collections
...
@@ -506,16 +540,16 @@ namespace Google.Protobuf.Collections
}
}
#
region
Explicit
interface
implementation
for
IList
and
ICollection
.
#
region
Explicit
interface
implementation
for
IList
and
ICollection
.
bool
IList
.
IsFixedSize
{
get
{
return
false
;
}
}
bool
IList
.
IsFixedSize
=>
false
;
void
ICollection
.
CopyTo
(
Array
array
,
int
index
)
void
ICollection
.
CopyTo
(
Array
array
,
int
index
)
{
{
Array
.
Copy
(
this
.
array
,
0
,
array
,
index
,
count
);
Array
.
Copy
(
this
.
array
,
0
,
array
,
index
,
count
);
}
}
bool
ICollection
.
IsSynchronized
{
get
{
return
false
;
}
}
bool
ICollection
.
IsSynchronized
=>
false
;
object
ICollection
.
SyncRoot
{
get
{
return
this
;
}
}
object
ICollection
.
SyncRoot
=>
this
;
object
IList
.
this
[
int
index
]
object
IList
.
this
[
int
index
]
{
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment