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
30b1454d
Commit
30b1454d
authored
Jul 15, 2014
by
Max Cai
Committed by
Gerrit Code Review
Jul 14, 2014
Browse files
Options
Browse Files
Download
Plain Diff
Merge "Keep pointers to extension values."
parents
70ef74aa
79f19eb9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
677 additions
and
47 deletions
+677
-47
README.txt
java/README.txt
+4
-3
ExtendableMessageNano.java
.../java/com/google/protobuf/nano/ExtendableMessageNano.java
+52
-19
Extension.java
java/src/main/java/com/google/protobuf/nano/Extension.java
+0
-0
FieldArray.java
java/src/main/java/com/google/protobuf/nano/FieldArray.java
+273
-0
FieldData.java
java/src/main/java/com/google/protobuf/nano/FieldData.java
+173
-0
UnknownFieldData.java
.../main/java/com/google/protobuf/nano/UnknownFieldData.java
+38
-25
NanoTest.java
java/src/test/java/com/google/protobuf/NanoTest.java
+137
-0
No files found.
java/README.txt
View file @
30b1454d
...
...
@@ -442,9 +442,10 @@ used simultaneously from multiple threads in a read-only manner.
In other words, an appropriate synchronization mechanism (such as
a ReadWriteLock) must be used to ensure that a message, its
ancestors, and descendants are not accessed by any other threads
while the message is being modified. Field reads, getter methods,
toByteArray(...), writeTo(...), getCachedSize(), and
getSerializedSize() are all considered read-only operations.
while the message is being modified. Field reads, getter methods
(but not getExtension(...)), toByteArray(...), writeTo(...),
getCachedSize(), and getSerializedSize() are all considered read-only
operations.
IMPORTANT: If you have fields with defaults and opt out of accessors
...
...
java/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java
View file @
30b1454d
...
...
@@ -31,8 +31,6 @@
package
com
.
google
.
protobuf
.
nano
;
import
java.io.IOException
;
import
java.util.ArrayList
;
import
java.util.List
;
/**
* Base class of those Protocol Buffer messages that need to store unknown fields,
...
...
@@ -44,27 +42,28 @@ public abstract class ExtendableMessageNano<M extends ExtendableMessageNano<M>>
* A container for fields unknown to the message, including extensions. Extension fields can
* can be accessed through the {@link #getExtension} and {@link #setExtension} methods.
*/
protected
List
<
UnknownFieldData
>
unknownFieldData
;
protected
FieldArray
unknownFieldData
;
@Override
protected
int
computeSerializedSize
()
{
int
size
=
0
;
i
nt
unknownFieldCount
=
unknownFieldData
==
null
?
0
:
unknownFieldData
.
size
();
for
(
int
i
=
0
;
i
<
unknownFieldCount
;
i
++)
{
UnknownFieldData
unknownField
=
unknownFieldData
.
ge
t
(
i
);
size
+=
CodedOutputByteBufferNano
.
computeRawVarint32Size
(
unknownField
.
tag
);
size
+=
unknownField
.
bytes
.
length
;
i
f
(
unknownFieldData
!=
null
)
{
for
(
int
i
=
0
;
i
<
unknownFieldData
.
size
()
;
i
++)
{
FieldData
field
=
unknownFieldData
.
dataA
t
(
i
);
size
+=
field
.
computeSerializedSize
(
);
}
}
return
size
;
}
@Override
public
void
writeTo
(
CodedOutputByteBufferNano
output
)
throws
IOException
{
int
unknownFieldCount
=
unknownFieldData
==
null
?
0
:
unknownFieldData
.
size
();
for
(
int
i
=
0
;
i
<
unknownFieldCount
;
i
++)
{
UnknownFieldData
unknownField
=
unknownFieldData
.
get
(
i
);
output
.
writeRawVarint32
(
unknownField
.
tag
);
output
.
writeRawBytes
(
unknownField
.
bytes
);
if
(
unknownFieldData
==
null
)
{
return
;
}
for
(
int
i
=
0
;
i
<
unknownFieldData
.
size
();
i
++)
{
FieldData
field
=
unknownFieldData
.
dataAt
(
i
);
field
.
writeTo
(
output
);
}
}
...
...
@@ -72,14 +71,38 @@ public abstract class ExtendableMessageNano<M extends ExtendableMessageNano<M>>
* Gets the value stored in the specified extension of this message.
*/
public
final
<
T
>
T
getExtension
(
Extension
<
M
,
T
>
extension
)
{
return
extension
.
getValueFrom
(
unknownFieldData
);
if
(
unknownFieldData
==
null
)
{
return
null
;
}
FieldData
field
=
unknownFieldData
.
get
(
WireFormatNano
.
getTagFieldNumber
(
extension
.
tag
));
return
field
==
null
?
null
:
field
.
getValue
(
extension
);
}
/**
* Sets the value of the specified extension of this message.
*/
public
final
<
T
>
M
setExtension
(
Extension
<
M
,
T
>
extension
,
T
value
)
{
unknownFieldData
=
extension
.
setValueTo
(
value
,
unknownFieldData
);
int
fieldNumber
=
WireFormatNano
.
getTagFieldNumber
(
extension
.
tag
);
if
(
value
==
null
)
{
if
(
unknownFieldData
!=
null
)
{
unknownFieldData
.
remove
(
fieldNumber
);
if
(
unknownFieldData
.
isEmpty
())
{
unknownFieldData
=
null
;
}
}
}
else
{
FieldData
field
=
null
;
if
(
unknownFieldData
==
null
)
{
unknownFieldData
=
new
FieldArray
();
}
else
{
field
=
unknownFieldData
.
get
(
fieldNumber
);
}
if
(
field
==
null
)
{
unknownFieldData
.
put
(
fieldNumber
,
new
FieldData
(
extension
,
value
));
}
else
{
field
.
setValue
(
extension
,
value
);
}
}
@SuppressWarnings
(
"unchecked"
)
// Generated code should guarantee type safety
M
typedThis
=
(
M
)
this
;
...
...
@@ -106,12 +129,22 @@ public abstract class ExtendableMessageNano<M extends ExtendableMessageNano<M>>
if
(!
input
.
skipField
(
tag
))
{
return
false
;
// This wasn't an unknown field, it's an end-group tag.
}
if
(
unknownFieldData
==
null
)
{
unknownFieldData
=
new
ArrayList
<
UnknownFieldData
>();
}
int
fieldNumber
=
WireFormatNano
.
getTagFieldNumber
(
tag
);
int
endPos
=
input
.
getPosition
();
byte
[]
bytes
=
input
.
getData
(
startPos
,
endPos
-
startPos
);
unknownFieldData
.
add
(
new
UnknownFieldData
(
tag
,
bytes
));
UnknownFieldData
unknownField
=
new
UnknownFieldData
(
tag
,
bytes
);
FieldData
field
=
null
;
if
(
unknownFieldData
==
null
)
{
unknownFieldData
=
new
FieldArray
();
}
else
{
field
=
unknownFieldData
.
get
(
fieldNumber
);
}
if
(
field
==
null
)
{
field
=
new
FieldData
();
unknownFieldData
.
put
(
fieldNumber
,
field
);
}
field
.
addUnknownField
(
unknownField
);
return
true
;
}
}
java/src/main/java/com/google/protobuf/nano/Extension.java
View file @
30b1454d
This diff is collapsed.
Click to expand it.
java/src/main/java/com/google/protobuf/nano/FieldArray.java
0 → 100644
View file @
30b1454d
// Protocol Buffers - Google's data interchange format
// Copyright 2014 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package
com
.
google
.
protobuf
.
nano
;
/**
* A custom version of {@link android.util.SparseArray} with the minimal API
* for storing {@link FieldData} objects.
*
* Based on {@link android.support.v4.util.SpareArrayCompat}.
*/
class
FieldArray
{
private
static
final
FieldData
DELETED
=
new
FieldData
();
private
boolean
mGarbage
=
false
;
private
int
[]
mFieldNumbers
;
private
FieldData
[]
mData
;
private
int
mSize
;
/**
* Creates a new FieldArray containing no fields.
*/
public
FieldArray
()
{
this
(
10
);
}
/**
* Creates a new FieldArray containing no mappings that will not
* require any additional memory allocation to store the specified
* number of mappings.
*/
public
FieldArray
(
int
initialCapacity
)
{
initialCapacity
=
idealIntArraySize
(
initialCapacity
);
mFieldNumbers
=
new
int
[
initialCapacity
];
mData
=
new
FieldData
[
initialCapacity
];
mSize
=
0
;
}
/**
* Gets the FieldData mapped from the specified fieldNumber, or <code>null</code>
* if no such mapping has been made.
*/
public
FieldData
get
(
int
fieldNumber
)
{
int
i
=
binarySearch
(
fieldNumber
);
if
(
i
<
0
||
mData
[
i
]
==
DELETED
)
{
return
null
;
}
else
{
return
mData
[
i
];
}
}
/**
* Removes the data from the specified fieldNumber, if there was any.
*/
public
void
remove
(
int
fieldNumber
)
{
int
i
=
binarySearch
(
fieldNumber
);
if
(
i
>=
0
&&
mData
[
i
]
!=
DELETED
)
{
mData
[
i
]
=
DELETED
;
mGarbage
=
true
;
}
}
private
void
gc
()
{
int
n
=
mSize
;
int
o
=
0
;
int
[]
keys
=
mFieldNumbers
;
FieldData
[]
values
=
mData
;
for
(
int
i
=
0
;
i
<
n
;
i
++)
{
FieldData
val
=
values
[
i
];
if
(
val
!=
DELETED
)
{
if
(
i
!=
o
)
{
keys
[
o
]
=
keys
[
i
];
values
[
o
]
=
val
;
values
[
i
]
=
null
;
}
o
++;
}
}
mGarbage
=
false
;
mSize
=
o
;
}
/**
* Adds a mapping from the specified fieldNumber to the specified data,
* replacing the previous mapping if there was one.
*/
public
void
put
(
int
fieldNumber
,
FieldData
data
)
{
int
i
=
binarySearch
(
fieldNumber
);
if
(
i
>=
0
)
{
mData
[
i
]
=
data
;
}
else
{
i
=
~
i
;
if
(
i
<
mSize
&&
mData
[
i
]
==
DELETED
)
{
mFieldNumbers
[
i
]
=
fieldNumber
;
mData
[
i
]
=
data
;
return
;
}
if
(
mGarbage
&&
mSize
>=
mFieldNumbers
.
length
)
{
gc
();
// Search again because indices may have changed.
i
=
~
binarySearch
(
fieldNumber
);
}
if
(
mSize
>=
mFieldNumbers
.
length
)
{
int
n
=
idealIntArraySize
(
mSize
+
1
);
int
[]
nkeys
=
new
int
[
n
];
FieldData
[]
nvalues
=
new
FieldData
[
n
];
System
.
arraycopy
(
mFieldNumbers
,
0
,
nkeys
,
0
,
mFieldNumbers
.
length
);
System
.
arraycopy
(
mData
,
0
,
nvalues
,
0
,
mData
.
length
);
mFieldNumbers
=
nkeys
;
mData
=
nvalues
;
}
if
(
mSize
-
i
!=
0
)
{
System
.
arraycopy
(
mFieldNumbers
,
i
,
mFieldNumbers
,
i
+
1
,
mSize
-
i
);
System
.
arraycopy
(
mData
,
i
,
mData
,
i
+
1
,
mSize
-
i
);
}
mFieldNumbers
[
i
]
=
fieldNumber
;
mData
[
i
]
=
data
;
mSize
++;
}
}
/**
* Returns the number of key-value mappings that this FieldArray
* currently stores.
*/
public
int
size
()
{
if
(
mGarbage
)
{
gc
();
}
return
mSize
;
}
public
boolean
isEmpty
()
{
return
size
()
==
0
;
}
/**
* Given an index in the range <code>0...size()-1</code>, returns
* the value from the <code>index</code>th key-value mapping that this
* FieldArray stores.
*/
public
FieldData
dataAt
(
int
index
)
{
if
(
mGarbage
)
{
gc
();
}
return
mData
[
index
];
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
o
==
this
)
{
return
true
;
}
if
(!(
o
instanceof
FieldArray
))
{
return
false
;
}
FieldArray
other
=
(
FieldArray
)
o
;
if
(
size
()
!=
other
.
size
())
{
// size() will call gc() if necessary.
return
false
;
}
return
arrayEquals
(
mFieldNumbers
,
other
.
mFieldNumbers
,
mSize
)
&&
arrayEquals
(
mData
,
other
.
mData
,
mSize
);
}
@Override
public
int
hashCode
()
{
if
(
mGarbage
)
{
gc
();
}
int
result
=
17
;
for
(
int
i
=
0
;
i
<
mSize
;
i
++)
{
result
=
31
*
result
+
mFieldNumbers
[
i
];
result
=
31
*
result
+
mData
[
i
].
hashCode
();
}
return
result
;
}
private
int
idealIntArraySize
(
int
need
)
{
return
idealByteArraySize
(
need
*
4
)
/
4
;
}
private
int
idealByteArraySize
(
int
need
)
{
for
(
int
i
=
4
;
i
<
32
;
i
++)
if
(
need
<=
(
1
<<
i
)
-
12
)
return
(
1
<<
i
)
-
12
;
return
need
;
}
private
int
binarySearch
(
int
value
)
{
int
lo
=
0
;
int
hi
=
mSize
-
1
;
while
(
lo
<=
hi
)
{
int
mid
=
(
lo
+
hi
)
>>>
1
;
int
midVal
=
mFieldNumbers
[
mid
];
if
(
midVal
<
value
)
{
lo
=
mid
+
1
;
}
else
if
(
midVal
>
value
)
{
hi
=
mid
-
1
;
}
else
{
return
mid
;
// value found
}
}
return
~
lo
;
// value not present
}
private
boolean
arrayEquals
(
int
[]
a
,
int
[]
b
,
int
size
)
{
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
if
(
a
[
i
]
!=
b
[
i
])
{
return
false
;
}
}
return
true
;
}
private
boolean
arrayEquals
(
FieldData
[]
a
,
FieldData
[]
b
,
int
size
)
{
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
if
(!
a
[
i
].
equals
(
b
[
i
]))
{
return
false
;
}
}
return
true
;
}
}
java/src/main/java/com/google/protobuf/nano/FieldData.java
0 → 100644
View file @
30b1454d
// Protocol Buffers - Google's data interchange format
// Copyright 2014 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package
com
.
google
.
protobuf
.
nano
;
import
java.io.IOException
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.List
;
/**
* Stores unknown fields. These might be extensions or fields that the generated API doesn't
* know about yet.
*/
class
FieldData
{
private
Extension
<?,
?>
cachedExtension
;
private
Object
value
;
/** The serialised values for this object. Will be cleared if getValue is called */
private
List
<
UnknownFieldData
>
unknownFieldData
;
<
T
>
FieldData
(
Extension
<?,
T
>
extension
,
T
newValue
)
{
cachedExtension
=
extension
;
value
=
newValue
;
}
FieldData
()
{
unknownFieldData
=
new
ArrayList
<
UnknownFieldData
>();
}
void
addUnknownField
(
UnknownFieldData
unknownField
)
{
unknownFieldData
.
add
(
unknownField
);
}
<
T
>
T
getValue
(
Extension
<?,
T
>
extension
)
{
if
(
value
!=
null
){
if
(
cachedExtension
!=
extension
)
{
// Extension objects are singletons.
throw
new
IllegalStateException
(
"Tried to getExtension with a differernt Extension."
);
}
}
else
{
cachedExtension
=
extension
;
value
=
extension
.
getValueFrom
(
unknownFieldData
);
unknownFieldData
=
null
;
}
return
(
T
)
value
;
}
<
T
>
void
setValue
(
Extension
<?,
T
>
extension
,
T
newValue
)
{
cachedExtension
=
extension
;
value
=
newValue
;
unknownFieldData
=
null
;
}
int
computeSerializedSize
()
{
int
size
=
0
;
if
(
value
!=
null
)
{
size
=
cachedExtension
.
computeSerializedSize
(
value
);
}
else
{
for
(
UnknownFieldData
unknownField
:
unknownFieldData
)
{
size
+=
unknownField
.
computeSerializedSize
();
}
}
return
size
;
}
void
writeTo
(
CodedOutputByteBufferNano
output
)
throws
IOException
{
if
(
value
!=
null
)
{
cachedExtension
.
writeTo
(
value
,
output
);
}
else
{
for
(
UnknownFieldData
unknownField
:
unknownFieldData
)
{
unknownField
.
writeTo
(
output
);
}
}
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
o
==
this
)
{
return
true
;
}
if
(!(
o
instanceof
FieldData
))
{
return
false
;
}
FieldData
other
=
(
FieldData
)
o
;
if
(
value
!=
null
&&
other
.
value
!=
null
)
{
// If both objects have deserialized values, compare those.
// Since unknown fields are only compared if messages have generated equals methods
// we know this will be a meaningful comparison (not identity) for all values.
if
(
cachedExtension
!=
other
.
cachedExtension
)
{
// Extension objects are singletons.
return
false
;
}
if
(!
cachedExtension
.
clazz
.
isArray
())
{
// Can't test (!cachedExtension.repeated) due to 'bytes' -> 'byte[]'
return
value
.
equals
(
other
.
value
);
}
if
(
value
instanceof
byte
[])
{
return
Arrays
.
equals
((
byte
[])
value
,
(
byte
[])
other
.
value
);
}
else
if
(
value
instanceof
int
[])
{
return
Arrays
.
equals
((
int
[])
value
,
(
int
[])
other
.
value
);
}
else
if
(
value
instanceof
long
[])
{
return
Arrays
.
equals
((
long
[])
value
,
(
long
[])
other
.
value
);
}
else
if
(
value
instanceof
float
[])
{
return
Arrays
.
equals
((
float
[])
value
,
(
float
[])
other
.
value
);
}
else
if
(
value
instanceof
double
[])
{
return
Arrays
.
equals
((
double
[])
value
,
(
double
[])
other
.
value
);
}
else
if
(
value
instanceof
boolean
[])
{
return
Arrays
.
equals
((
boolean
[])
value
,
(
boolean
[])
other
.
value
);
}
else
{
return
Arrays
.
deepEquals
((
Object
[])
value
,
(
Object
[])
other
.
value
);
}
}
if
(
unknownFieldData
!=
null
&&
other
.
unknownFieldData
!=
null
)
{
// If both objects have byte arrays compare those directly.
return
unknownFieldData
.
equals
(
other
.
unknownFieldData
);
}
try
{
// As a last resort, serialize and compare the resulting byte arrays.
return
Arrays
.
equals
(
toByteArray
(),
other
.
toByteArray
());
}
catch
(
IOException
e
)
{
// Should not happen.
throw
new
IllegalStateException
(
e
);
}
}
@Override
public
int
hashCode
()
{
int
result
=
17
;
try
{
// The only way to generate a consistent hash is to use the serialized form.
result
=
31
*
result
+
Arrays
.
hashCode
(
toByteArray
());
}
catch
(
IOException
e
)
{
// Should not happen.
throw
new
IllegalStateException
(
e
);
}
return
result
;
}
private
byte
[]
toByteArray
()
throws
IOException
{
byte
[]
result
=
new
byte
[
computeSerializedSize
()];
CodedOutputByteBufferNano
output
=
CodedOutputByteBufferNano
.
newInstance
(
result
);
writeTo
(
output
);
return
result
;
}
}
java/src/main/java/com/google/protobuf/nano/UnknownFieldData.java
View file @
30b1454d
...
...
@@ -30,42 +30,55 @@
package
com
.
google
.
protobuf
.
nano
;
import
java.io.IOException
;
import
java.util.Arrays
;
/**
* Stores unknown fields. These might be extensions or fields that the generated
API doesn't
* know about yet.
* Stores unknown fields. These might be extensions or fields that the generated
*
API doesn't
know about yet.
*
* @author bduff@google.com (Brian Duff)
*/
public
final
class
UnknownFieldData
{
final
class
UnknownFieldData
{
final
int
tag
;
final
byte
[]
bytes
;
final
int
tag
;
final
byte
[]
bytes
;
UnknownFieldData
(
int
tag
,
byte
[]
bytes
)
{
this
.
tag
=
tag
;
this
.
bytes
=
bytes
;
}
UnknownFieldData
(
int
tag
,
byte
[]
bytes
)
{
this
.
tag
=
tag
;
this
.
bytes
=
bytes
;
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
o
==
this
)
{
return
true
;
int
computeSerializedSize
()
{
int
size
=
0
;
size
+=
CodedOutputByteBufferNano
.
computeRawVarint32Size
(
tag
);
size
+=
bytes
.
length
;
return
size
;
}
if
(!(
o
instanceof
UnknownFieldData
))
{
return
false
;
void
writeTo
(
CodedOutputByteBufferNano
output
)
throws
IOException
{
output
.
writeRawVarint32
(
tag
);
output
.
writeRawBytes
(
bytes
);
}
UnknownFieldData
other
=
(
UnknownFieldData
)
o
;
return
tag
==
other
.
tag
&&
Arrays
.
equals
(
bytes
,
other
.
bytes
);
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
o
==
this
)
{
return
true
;
}
if
(!(
o
instanceof
UnknownFieldData
))
{
return
false
;
}
@Override
public
int
hashCode
()
{
int
result
=
17
;
result
=
31
*
result
+
tag
;
result
=
31
*
result
+
Arrays
.
hashCode
(
bytes
);
return
result
;
}
UnknownFieldData
other
=
(
UnknownFieldData
)
o
;
return
tag
==
other
.
tag
&&
Arrays
.
equals
(
bytes
,
other
.
bytes
);
}
@Override
public
int
hashCode
()
{
int
result
=
17
;
result
=
31
*
result
+
tag
;
result
=
31
*
result
+
Arrays
.
hashCode
(
bytes
);
return
result
;
}
}
java/src/test/java/com/google/protobuf/NanoTest.java
View file @
30b1454d
...
...
@@ -41,6 +41,7 @@ import com.google.protobuf.nano.Extensions.MessageWithGroup;
import
com.google.protobuf.nano.FileScopeEnumMultiple
;
import
com.google.protobuf.nano.FileScopeEnumRefNano
;
import
com.google.protobuf.nano.InternalNano
;
import
com.google.protobuf.nano.InvalidProtocolBufferNanoException
;
import
com.google.protobuf.nano.MessageNano
;
import
com.google.protobuf.nano.MessageScopeEnumRefNano
;
import
com.google.protobuf.nano.MultipleImportingNonMultipleNano1
;
...
...
@@ -2826,6 +2827,8 @@ public class NanoTest extends TestCase {
assertEquals
(
group2
.
a
,
message
.
getExtension
(
SingularExtensions
.
someGroup
).
a
);
// Test reading back using RepeatedExtensions: the arrays should be equal.
message
=
Extensions
.
ExtendableMessage
.
parseFrom
(
data
);
assertEquals
(
5
,
message
.
field
);
assertTrue
(
Arrays
.
equals
(
int32s
,
message
.
getExtension
(
RepeatedExtensions
.
repeatedInt32
)));
assertTrue
(
Arrays
.
equals
(
uint32s
,
message
.
getExtension
(
RepeatedExtensions
.
repeatedUint32
)));
assertTrue
(
Arrays
.
equals
(
sint32s
,
message
.
getExtension
(
RepeatedExtensions
.
repeatedSint32
)));
...
...
@@ -2860,6 +2863,8 @@ public class NanoTest extends TestCase {
// Test reading back using PackedExtensions: the arrays should be equal, even the fields
// are non-packed.
message
=
Extensions
.
ExtendableMessage
.
parseFrom
(
data
);
assertEquals
(
5
,
message
.
field
);
assertTrue
(
Arrays
.
equals
(
int32s
,
message
.
getExtension
(
PackedExtensions
.
packedInt32
)));
assertTrue
(
Arrays
.
equals
(
uint32s
,
message
.
getExtension
(
PackedExtensions
.
packedUint32
)));
assertTrue
(
Arrays
.
equals
(
sint32s
,
message
.
getExtension
(
PackedExtensions
.
packedSint32
)));
...
...
@@ -2924,6 +2929,138 @@ public class NanoTest extends TestCase {
assertEquals
(
0
,
MessageNano
.
toByteArray
(
message
).
length
);
}
public
void
testExtensionsMutation
()
{
Extensions
.
ExtendableMessage
extendableMessage
=
new
Extensions
.
ExtendableMessage
();
extendableMessage
.
setExtension
(
SingularExtensions
.
someMessage
,
new
Extensions
.
AnotherMessage
());
extendableMessage
.
getExtension
(
SingularExtensions
.
someMessage
).
string
=
"not empty"
;
assertEquals
(
"not empty"
,
extendableMessage
.
getExtension
(
SingularExtensions
.
someMessage
).
string
);
}
public
void
testExtensionsMutation_Equals
()
throws
InvalidProtocolBufferNanoException
{
Extensions
.
ExtendableMessage
extendableMessage
=
new
Extensions
.
ExtendableMessage
();
extendableMessage
.
field
=
5
;
int
int32
=
42
;
int
[]
uint32s
=
{
3
,
4
};
int
[]
sint32s
=
{-
5
,
-
6
};
long
[]
int64s
=
{
7
,
8
};
long
[]
uint64s
=
{
9
,
10
};
long
[]
sint64s
=
{-
11
,
-
12
};
int
[]
fixed32s
=
{
13
,
14
};
int
[]
sfixed32s
=
{-
15
,
-
16
};
long
[]
fixed64s
=
{
17
,
18
};
long
[]
sfixed64s
=
{-
19
,
-
20
};
boolean
[]
bools
=
{
true
,
false
};
float
[]
floats
=
{
2.1f
,
2.2f
};
double
[]
doubles
=
{
2.3
,
2.4
};
int
[]
enums
=
{
Extensions
.
SECOND_VALUE
,
Extensions
.
FIRST_VALUE
};
String
[]
strings
=
{
"vijfentwintig"
,
"twenty-six"
};
byte
[][]
bytess
=
{{
2
,
7
},
{
2
,
8
}};
AnotherMessage
another1
=
new
AnotherMessage
();
another1
.
string
=
"er shi jiu"
;
another1
.
value
=
false
;
AnotherMessage
another2
=
new
AnotherMessage
();
another2
.
string
=
"trente"
;
another2
.
value
=
true
;
AnotherMessage
[]
messages
=
{
another1
,
another2
};
RepeatedExtensions
.
RepeatedGroup
group1
=
new
RepeatedExtensions
.
RepeatedGroup
();
group1
.
a
=
31
;
RepeatedExtensions
.
RepeatedGroup
group2
=
new
RepeatedExtensions
.
RepeatedGroup
();
group2
.
a
=
32
;
RepeatedExtensions
.
RepeatedGroup
[]
groups
=
{
group1
,
group2
};
extendableMessage
.
setExtension
(
SingularExtensions
.
someInt32
,
int32
);
extendableMessage
.
setExtension
(
RepeatedExtensions
.
repeatedUint32
,
uint32s
);
extendableMessage
.
setExtension
(
RepeatedExtensions
.
repeatedSint32
,
sint32s
);
extendableMessage
.
setExtension
(
RepeatedExtensions
.
repeatedInt64
,
int64s
);
extendableMessage
.
setExtension
(
RepeatedExtensions
.
repeatedUint64
,
uint64s
);
extendableMessage
.
setExtension
(
RepeatedExtensions
.
repeatedSint64
,
sint64s
);
extendableMessage
.
setExtension
(
RepeatedExtensions
.
repeatedFixed32
,
fixed32s
);
extendableMessage
.
setExtension
(
RepeatedExtensions
.
repeatedSfixed32
,
sfixed32s
);
extendableMessage
.
setExtension
(
RepeatedExtensions
.
repeatedFixed64
,
fixed64s
);
extendableMessage
.
setExtension
(
RepeatedExtensions
.
repeatedSfixed64
,
sfixed64s
);
extendableMessage
.
setExtension
(
RepeatedExtensions
.
repeatedBool
,
bools
);
extendableMessage
.
setExtension
(
RepeatedExtensions
.
repeatedFloat
,
floats
);
extendableMessage
.
setExtension
(
RepeatedExtensions
.
repeatedDouble
,
doubles
);
extendableMessage
.
setExtension
(
RepeatedExtensions
.
repeatedEnum
,
enums
);
extendableMessage
.
setExtension
(
RepeatedExtensions
.
repeatedString
,
strings
);
extendableMessage
.
setExtension
(
RepeatedExtensions
.
repeatedBytes
,
bytess
);
extendableMessage
.
setExtension
(
RepeatedExtensions
.
repeatedMessage
,
messages
);
extendableMessage
.
setExtension
(
RepeatedExtensions
.
repeatedGroup
,
groups
);
byte
[]
data
=
MessageNano
.
toByteArray
(
extendableMessage
);
extendableMessage
=
Extensions
.
ExtendableMessage
.
parseFrom
(
data
);
Extensions
.
ExtendableMessage
messageCopy
=
Extensions
.
ExtendableMessage
.
parseFrom
(
data
);
// Without deserialising.
assertEquals
(
extendableMessage
,
messageCopy
);
assertEquals
(
extendableMessage
.
hashCode
(),
messageCopy
.
hashCode
());
// Only one deserialized.
extendableMessage
.
getExtension
(
SingularExtensions
.
someInt32
);
extendableMessage
.
getExtension
(
RepeatedExtensions
.
repeatedUint32
);
extendableMessage
.
getExtension
(
RepeatedExtensions
.
repeatedSint32
);
extendableMessage
.
getExtension
(
RepeatedExtensions
.
repeatedInt64
);
extendableMessage
.
getExtension
(
RepeatedExtensions
.
repeatedUint64
);
extendableMessage
.
getExtension
(
RepeatedExtensions
.
repeatedSint64
);
extendableMessage
.
getExtension
(
RepeatedExtensions
.
repeatedFixed32
);
extendableMessage
.
getExtension
(
RepeatedExtensions
.
repeatedSfixed32
);
extendableMessage
.
getExtension
(
RepeatedExtensions
.
repeatedFixed64
);
extendableMessage
.
getExtension
(
RepeatedExtensions
.
repeatedSfixed64
);
extendableMessage
.
getExtension
(
RepeatedExtensions
.
repeatedBool
);
extendableMessage
.
getExtension
(
RepeatedExtensions
.
repeatedFloat
);
extendableMessage
.
getExtension
(
RepeatedExtensions
.
repeatedDouble
);
extendableMessage
.
getExtension
(
RepeatedExtensions
.
repeatedEnum
);
extendableMessage
.
getExtension
(
RepeatedExtensions
.
repeatedString
);
extendableMessage
.
getExtension
(
RepeatedExtensions
.
repeatedBytes
);
extendableMessage
.
getExtension
(
RepeatedExtensions
.
repeatedMessage
);
extendableMessage
.
getExtension
(
RepeatedExtensions
.
repeatedGroup
);
assertEquals
(
extendableMessage
,
messageCopy
);
assertEquals
(
extendableMessage
.
hashCode
(),
messageCopy
.
hashCode
());
// Both deserialized.
messageCopy
.
getExtension
(
SingularExtensions
.
someInt32
);
messageCopy
.
getExtension
(
RepeatedExtensions
.
repeatedUint32
);
messageCopy
.
getExtension
(
RepeatedExtensions
.
repeatedSint32
);
messageCopy
.
getExtension
(
RepeatedExtensions
.
repeatedInt64
);
messageCopy
.
getExtension
(
RepeatedExtensions
.
repeatedUint64
);
messageCopy
.
getExtension
(
RepeatedExtensions
.
repeatedSint64
);
messageCopy
.
getExtension
(
RepeatedExtensions
.
repeatedFixed32
);
messageCopy
.
getExtension
(
RepeatedExtensions
.
repeatedSfixed32
);
messageCopy
.
getExtension
(
RepeatedExtensions
.
repeatedFixed64
);
messageCopy
.
getExtension
(
RepeatedExtensions
.
repeatedSfixed64
);
messageCopy
.
getExtension
(
RepeatedExtensions
.
repeatedBool
);
messageCopy
.
getExtension
(
RepeatedExtensions
.
repeatedFloat
);
messageCopy
.
getExtension
(
RepeatedExtensions
.
repeatedDouble
);
messageCopy
.
getExtension
(
RepeatedExtensions
.
repeatedEnum
);
messageCopy
.
getExtension
(
RepeatedExtensions
.
repeatedString
);
messageCopy
.
getExtension
(
RepeatedExtensions
.
repeatedBytes
);
messageCopy
.
getExtension
(
RepeatedExtensions
.
repeatedMessage
);
messageCopy
.
getExtension
(
RepeatedExtensions
.
repeatedGroup
);
assertEquals
(
extendableMessage
,
messageCopy
);
assertEquals
(
extendableMessage
.
hashCode
(),
messageCopy
.
hashCode
());
// Change one, make sure they are still different.
messageCopy
.
getExtension
(
RepeatedExtensions
.
repeatedMessage
)[
0
].
string
=
"not empty"
;
assertFalse
(
extendableMessage
.
equals
(
messageCopy
));
// Even if the extension hasn't been deserialized.
extendableMessage
=
Extensions
.
ExtendableMessage
.
parseFrom
(
data
);
assertFalse
(
extendableMessage
.
equals
(
messageCopy
));
}
public
void
testExtensionsCaching
()
{
Extensions
.
ExtendableMessage
extendableMessage
=
new
Extensions
.
ExtendableMessage
();
extendableMessage
.
setExtension
(
SingularExtensions
.
someMessage
,
new
Extensions
.
AnotherMessage
());
assertSame
(
"Consecutive calls to getExtensions should return the same object"
,
extendableMessage
.
getExtension
(
SingularExtensions
.
someMessage
),
extendableMessage
.
getExtension
(
SingularExtensions
.
someMessage
));
}
public
void
testUnknownFields
()
throws
Exception
{
// Check that we roundtrip (serialize and deserialize) unrecognized fields.
AnotherMessage
message
=
new
AnotherMessage
();
...
...
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