commit
2cb2358cba
15 changed files with 1163 additions and 87 deletions
@ -0,0 +1,67 @@ |
|||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2013 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// 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.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* Utility class for maps support. |
||||||
|
*/ |
||||||
|
public final class MapFactories { |
||||||
|
public static interface MapFactory { |
||||||
|
<K, V> Map<K, V> forMap(Map<K, V> oldMap); |
||||||
|
} |
||||||
|
|
||||||
|
// NOTE(liujisi): The factory setter is temporarily marked as package private.
|
||||||
|
// The way to provide customized implementations of maps for different
|
||||||
|
// platforms are still under discussion. Mark it as private to avoid exposing
|
||||||
|
// the API in proto3 alpha release.
|
||||||
|
/* public */ static void setMapFactory(MapFactory newMapFactory) { |
||||||
|
mapFactory = newMapFactory; |
||||||
|
} |
||||||
|
|
||||||
|
public static MapFactory getMapFactory() { |
||||||
|
return mapFactory; |
||||||
|
} |
||||||
|
|
||||||
|
private static class DefaultMapFactory implements MapFactory { |
||||||
|
public <K, V> Map<K, V> forMap(Map<K, V> oldMap) { |
||||||
|
if (oldMap == null) { |
||||||
|
return new HashMap<K, V>(); |
||||||
|
} |
||||||
|
return oldMap; |
||||||
|
} |
||||||
|
} |
||||||
|
private static volatile MapFactory mapFactory = new DefaultMapFactory(); |
||||||
|
|
||||||
|
private MapFactories() {} |
||||||
|
} |
@ -0,0 +1,70 @@ |
|||||||
|
// Protocol Buffers - Google's data interchange format |
||||||
|
// Copyright 2008 Google Inc. All rights reserved. |
||||||
|
// https://developers.google.com/protocol-buffers/ |
||||||
|
// |
||||||
|
// 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. |
||||||
|
|
||||||
|
syntax = "proto3"; |
||||||
|
|
||||||
|
package map_test; |
||||||
|
|
||||||
|
option java_package = "com.google.protobuf.nano"; |
||||||
|
option java_outer_classname = "MapTestProto"; |
||||||
|
|
||||||
|
message TestMap { |
||||||
|
message MessageValue { |
||||||
|
int32 value = 1; |
||||||
|
int32 value2 = 2; |
||||||
|
} |
||||||
|
enum EnumValue { |
||||||
|
FOO = 0; |
||||||
|
BAR = 1; |
||||||
|
BAZ = 2; |
||||||
|
QUX = 3; |
||||||
|
} |
||||||
|
|
||||||
|
map<int32, int32> int32_to_int32_field = 1; |
||||||
|
map<int32, string> int32_to_string_field = 2; |
||||||
|
map<int32, bytes> int32_to_bytes_field = 3; |
||||||
|
map<int32, EnumValue> int32_to_enum_field = 4; |
||||||
|
map<int32, MessageValue> int32_to_message_field = 5; |
||||||
|
map<string, int32> string_to_int32_field = 6; |
||||||
|
map<bool, bool> bool_to_bool_field = 7; |
||||||
|
|
||||||
|
// Test all the other primitive types. As the key and value are not coupled in |
||||||
|
// the implementation, we do not test all the combinations of key/value pairs, |
||||||
|
// so that we can keep the number of test cases manageable |
||||||
|
map<uint32, uint32> uint32_to_uint32_field = 11; |
||||||
|
map<sint32, sint32> sint32_to_sint32_field = 12; |
||||||
|
map<fixed32, fixed32> fixed32_to_fixed32_field = 13; |
||||||
|
map<sfixed32, sfixed32> sfixed32_to_sfixed32_field = 14; |
||||||
|
map<int64, int64> int64_to_int64_field = 15; |
||||||
|
map<uint64, uint64> uint64_to_uint64_field = 16; |
||||||
|
map<sint64, sint64> sint64_to_sint64_field = 17; |
||||||
|
map<fixed64, fixed64> fixed64_to_fixed64_field = 18; |
||||||
|
map<sfixed64, sfixed64> sfixed64_to_sfixed64_field = 19; |
||||||
|
} |
@ -0,0 +1,186 @@ |
|||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 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.
|
||||||
|
|
||||||
|
#include <google/protobuf/compiler/javanano/javanano_map_field.h> |
||||||
|
#include <google/protobuf/compiler/javanano/javanano_helpers.h> |
||||||
|
#include <google/protobuf/stubs/common.h> |
||||||
|
#include <google/protobuf/io/printer.h> |
||||||
|
#include <google/protobuf/wire_format.h> |
||||||
|
#include <google/protobuf/stubs/strutil.h> |
||||||
|
|
||||||
|
namespace google { |
||||||
|
namespace protobuf { |
||||||
|
namespace compiler { |
||||||
|
namespace javanano { |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
string TypeName(const Params& params, const FieldDescriptor* field, |
||||||
|
bool boxed) { |
||||||
|
JavaType java_type = GetJavaType(field); |
||||||
|
switch (java_type) { |
||||||
|
case JAVATYPE_MESSAGE: |
||||||
|
return ClassName(params, field->message_type()); |
||||||
|
case JAVATYPE_INT: |
||||||
|
case JAVATYPE_LONG: |
||||||
|
case JAVATYPE_FLOAT: |
||||||
|
case JAVATYPE_DOUBLE: |
||||||
|
case JAVATYPE_BOOLEAN: |
||||||
|
case JAVATYPE_STRING: |
||||||
|
case JAVATYPE_BYTES: |
||||||
|
case JAVATYPE_ENUM: |
||||||
|
if (boxed) { |
||||||
|
return BoxedPrimitiveTypeName(java_type); |
||||||
|
} else { |
||||||
|
return PrimitiveTypeName(java_type); |
||||||
|
} |
||||||
|
// No default because we want the compiler to complain if any new JavaTypes
|
||||||
|
// are added..
|
||||||
|
} |
||||||
|
|
||||||
|
GOOGLE_LOG(FATAL) << "should not reach here."; |
||||||
|
return ""; |
||||||
|
} |
||||||
|
|
||||||
|
const FieldDescriptor* KeyField(const FieldDescriptor* descriptor) { |
||||||
|
GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type()); |
||||||
|
const Descriptor* message = descriptor->message_type(); |
||||||
|
GOOGLE_CHECK(message->options().map_entry()); |
||||||
|
return message->FindFieldByName("key"); |
||||||
|
} |
||||||
|
|
||||||
|
const FieldDescriptor* ValueField(const FieldDescriptor* descriptor) { |
||||||
|
GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type()); |
||||||
|
const Descriptor* message = descriptor->message_type(); |
||||||
|
GOOGLE_CHECK(message->options().map_entry()); |
||||||
|
return message->FindFieldByName("value"); |
||||||
|
} |
||||||
|
|
||||||
|
void SetMapVariables(const Params& params, |
||||||
|
const FieldDescriptor* descriptor, map<string, string>* variables) { |
||||||
|
const FieldDescriptor* key = KeyField(descriptor); |
||||||
|
const FieldDescriptor* value = ValueField(descriptor); |
||||||
|
(*variables)["name"] = |
||||||
|
RenameJavaKeywords(UnderscoresToCamelCase(descriptor)); |
||||||
|
(*variables)["number"] = SimpleItoa(descriptor->number()); |
||||||
|
(*variables)["key_type"] = TypeName(params, key, false); |
||||||
|
(*variables)["boxed_key_type"] = TypeName(params,key, true); |
||||||
|
(*variables)["key_desc_type"] = |
||||||
|
"TYPE_" + ToUpper(FieldDescriptor::TypeName(key->type())); |
||||||
|
(*variables)["key_tag"] = SimpleItoa(internal::WireFormat::MakeTag(key)); |
||||||
|
(*variables)["value_type"] = TypeName(params, value, false); |
||||||
|
(*variables)["boxed_value_type"] = TypeName(params, value, true); |
||||||
|
(*variables)["value_desc_type"] = |
||||||
|
"TYPE_" + ToUpper(FieldDescriptor::TypeName(value->type())); |
||||||
|
(*variables)["value_tag"] = SimpleItoa(internal::WireFormat::MakeTag(value)); |
||||||
|
(*variables)["type_parameters"] = |
||||||
|
(*variables)["boxed_key_type"] + ", " + (*variables)["boxed_value_type"]; |
||||||
|
(*variables)["value_default"] = |
||||||
|
value->type() == FieldDescriptor::TYPE_MESSAGE |
||||||
|
? "new " + (*variables)["value_type"] + "()" |
||||||
|
: "null"; |
||||||
|
} |
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// ===================================================================
|
||||||
|
MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor, |
||||||
|
const Params& params) |
||||||
|
: FieldGenerator(params), descriptor_(descriptor) { |
||||||
|
SetMapVariables(params, descriptor, &variables_); |
||||||
|
} |
||||||
|
|
||||||
|
MapFieldGenerator::~MapFieldGenerator() {} |
||||||
|
|
||||||
|
void MapFieldGenerator:: |
||||||
|
GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const { |
||||||
|
printer->Print(variables_, |
||||||
|
"public java.util.Map<$type_parameters$> $name$;\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void MapFieldGenerator:: |
||||||
|
GenerateClearCode(io::Printer* printer) const { |
||||||
|
printer->Print(variables_, |
||||||
|
"$name$ = null;\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void MapFieldGenerator:: |
||||||
|
GenerateMergingCode(io::Printer* printer) const { |
||||||
|
printer->Print(variables_, |
||||||
|
"this.$name$ = com.google.protobuf.nano.InternalNano.mergeMapEntry(\n" |
||||||
|
" input, this.$name$, mapFactory,\n" |
||||||
|
" com.google.protobuf.nano.InternalNano.$key_desc_type$,\n" |
||||||
|
" com.google.protobuf.nano.InternalNano.$value_desc_type$,\n" |
||||||
|
" $value_default$,\n" |
||||||
|
" $key_tag$, $value_tag$);\n" |
||||||
|
"\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void MapFieldGenerator:: |
||||||
|
GenerateSerializationCode(io::Printer* printer) const { |
||||||
|
printer->Print(variables_, |
||||||
|
"if (this.$name$ != null) {\n" |
||||||
|
" com.google.protobuf.nano.InternalNano.serializeMapField(\n" |
||||||
|
" output, this.$name$, $number$,\n" |
||||||
|
" com.google.protobuf.nano.InternalNano.$key_desc_type$,\n" |
||||||
|
" com.google.protobuf.nano.InternalNano.$value_desc_type$);\n" |
||||||
|
"}\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void MapFieldGenerator:: |
||||||
|
GenerateSerializedSizeCode(io::Printer* printer) const { |
||||||
|
printer->Print(variables_, |
||||||
|
"if (this.$name$ != null) {\n" |
||||||
|
" size += com.google.protobuf.nano.InternalNano.computeMapFieldSize(\n" |
||||||
|
" this.$name$, $number$,\n" |
||||||
|
" com.google.protobuf.nano.InternalNano.$key_desc_type$,\n" |
||||||
|
" com.google.protobuf.nano.InternalNano.$value_desc_type$);\n" |
||||||
|
"}\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void MapFieldGenerator:: |
||||||
|
GenerateEqualsCode(io::Printer* printer) const { |
||||||
|
printer->Print(variables_, |
||||||
|
"if (!com.google.protobuf.nano.InternalNano.equals(\n" |
||||||
|
" this.$name$, other.$name$)) {\n" |
||||||
|
" return false;\n" |
||||||
|
"}\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void MapFieldGenerator:: |
||||||
|
GenerateHashCodeCode(io::Printer* printer) const { |
||||||
|
printer->Print(variables_, |
||||||
|
"result = 31 * result +\n" |
||||||
|
" com.google.protobuf.nano.InternalNano.hashCode(this.$name$);\n"); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace javanano
|
||||||
|
} // namespace compiler
|
||||||
|
} // namespace protobuf
|
||||||
|
} // namespace google
|
@ -0,0 +1,70 @@ |
|||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 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.
|
||||||
|
|
||||||
|
#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_MAP_FIELD_H__ |
||||||
|
#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_MAP_FIELD_H__ |
||||||
|
|
||||||
|
#include <map> |
||||||
|
#include <string> |
||||||
|
#include <vector> |
||||||
|
#include <google/protobuf/compiler/javanano/javanano_field.h> |
||||||
|
|
||||||
|
namespace google { |
||||||
|
namespace protobuf { |
||||||
|
namespace compiler { |
||||||
|
namespace javanano { |
||||||
|
|
||||||
|
class MapFieldGenerator : public FieldGenerator { |
||||||
|
public: |
||||||
|
explicit MapFieldGenerator( |
||||||
|
const FieldDescriptor* descriptor, const Params& params); |
||||||
|
~MapFieldGenerator(); |
||||||
|
|
||||||
|
// implements FieldGenerator ---------------------------------------
|
||||||
|
void GenerateMembers(io::Printer* printer, bool lazy_init) const; |
||||||
|
void GenerateClearCode(io::Printer* printer) const; |
||||||
|
void GenerateMergingCode(io::Printer* printer) const; |
||||||
|
void GenerateSerializationCode(io::Printer* printer) const; |
||||||
|
void GenerateSerializedSizeCode(io::Printer* printer) const; |
||||||
|
void GenerateEqualsCode(io::Printer* printer) const; |
||||||
|
void GenerateHashCodeCode(io::Printer* printer) const; |
||||||
|
|
||||||
|
private: |
||||||
|
const FieldDescriptor* descriptor_; |
||||||
|
map<string, string> variables_; |
||||||
|
|
||||||
|
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator); |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace javanano
|
||||||
|
} // namespace compiler
|
||||||
|
} // namespace protobuf
|
||||||
|
} // namespace google
|
||||||
|
#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_MAP_FIELD_H__
|
Loading…
Reference in new issue