diff options
254 files changed, 84480 insertions, 321 deletions
@@ -51,6 +51,7 @@ cpp_test*.pb.* *.pyc *.egg-info *_pb2.py +python/*.egg python/.eggs/ python/build/ python/google/protobuf/compiler/ @@ -82,3 +83,9 @@ vsprojects/Release # NuGet packages: we want the repository configuration, but not the # packages themselves. /csharp/src/packages/*/ + +# Directories created by opening the Objective C Xcode projects. +objectivec/ProtocolBuffers_OSX.xcodeproj/project.xcworkspace/xcuserdata/ +objectivec/ProtocolBuffers_OSX.xcodeproj/xcuserdata/ +objectivec/ProtocolBuffers_iOS.xcodeproj/project.xcworkspace/xcuserdata/ +objectivec/ProtocolBuffers_iOS.xcodeproj/xcuserdata/ diff --git a/.travis.yml b/.travis.yml index cbddac58..354be896 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,7 @@ script: - cd python && python setup.py build && python setup.py test && cd .. - export LD_LIBRARY_PATH=../src/.libs - cd python && python setup.py build --cpp_implementation && python setup.py test --cpp_implementation && cd .. + - cd conformance && make test_java && cd .. - make distcheck -j2 notifications: email: false diff --git a/Makefile.am b/Makefile.am index 4fd93f26..eecffa1f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -197,6 +197,128 @@ javanano_EXTRA_DIST= javanano/README.md \ javanano/pom.xml +objectivec_EXTRA_DIST= \ + objectivec/DevTools/generate_descriptors_proto.sh \ + objectivec/DevTools/pddm.py \ + objectivec/DevTools/pddm_tests.py \ + objectivec/google/protobuf/Descriptor.pbobjc.h \ + objectivec/google/protobuf/Descriptor.pbobjc.m \ + objectivec/google/protobuf/Duration.pbobjc.h \ + objectivec/google/protobuf/Duration.pbobjc.m \ + objectivec/google/protobuf/Timestamp.pbobjc.h \ + objectivec/google/protobuf/Timestamp.pbobjc.m \ + objectivec/GPBArray.h \ + objectivec/GPBArray.m \ + objectivec/GPBArray_PackagePrivate.h \ + objectivec/GPBBootstrap.h \ + objectivec/GPBCodedInputStream.h \ + objectivec/GPBCodedInputStream.m \ + objectivec/GPBCodedInputStream_PackagePrivate.h \ + objectivec/GPBCodedOutputStream.h \ + objectivec/GPBCodedOutputStream.m \ + objectivec/GPBDescriptor.h \ + objectivec/GPBDescriptor.m \ + objectivec/GPBDescriptor_PackagePrivate.h \ + objectivec/GPBDictionary.h \ + objectivec/GPBDictionary.m \ + objectivec/GPBDictionary_PackagePrivate.h \ + objectivec/GPBExtensionField.h \ + objectivec/GPBExtensionField.m \ + objectivec/GPBExtensionField_PackagePrivate.h \ + objectivec/GPBExtensionRegistry.h \ + objectivec/GPBExtensionRegistry.m \ + objectivec/GPBExtensionRegistry_PackagePrivate.h \ + objectivec/GPBField.h \ + objectivec/GPBField.m \ + objectivec/GPBField_PackagePrivate.h \ + objectivec/GPBMessage.h \ + objectivec/GPBMessage.m \ + objectivec/GPBMessage_PackagePrivate.h \ + objectivec/GPBProtocolBuffers.h \ + objectivec/GPBProtocolBuffers.m \ + objectivec/GPBProtocolBuffers_RuntimeSupport.h \ + objectivec/GPBRootObject.h \ + objectivec/GPBRootObject.m \ + objectivec/GPBRootObject_PackagePrivate.h \ + objectivec/GPBTypes.h \ + objectivec/GPBUnknownFieldSet.h \ + objectivec/GPBUnknownFieldSet.m \ + objectivec/GPBUnknownFieldSet_PackagePrivate.h \ + objectivec/GPBUtilities.h \ + objectivec/GPBUtilities.m \ + objectivec/GPBUtilities_PackagePrivate.h \ + objectivec/GPBWellKnownTypes.h \ + objectivec/GPBWellKnownTypes.m \ + objectivec/GPBWireFormat.h \ + objectivec/GPBWireFormat.m \ + objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj \ + objectivec/ProtocolBuffers_iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata \ + objectivec/ProtocolBuffers_iOS.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings \ + objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcbaselines/8BBEA4A5147C727100C4ADB7.xcbaseline/FFE465CA-0E74-40E8-9F09-500B66B7DCB2.plist \ + objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcbaselines/8BBEA4A5147C727100C4ADB7.xcbaseline/Info.plist \ + objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme \ + objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme \ + objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj \ + objectivec/ProtocolBuffers_OSX.xcodeproj/project.xcworkspace/contents.xcworkspacedata \ + objectivec/ProtocolBuffers_OSX.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings \ + objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme \ + objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme \ + objectivec/Tests/Filter1.txt \ + objectivec/Tests/Filter2.txt \ + objectivec/Tests/golden_message \ + objectivec/Tests/golden_packed_fields_message \ + objectivec/Tests/GPBARCUnittestProtos.m \ + objectivec/Tests/GPBArrayTests.m \ + objectivec/Tests/GPBCodedInputStreamTests.m \ + objectivec/Tests/GPBCodedOuputStreamTests.m \ + objectivec/Tests/GPBConcurrencyTests.m \ + objectivec/Tests/GPBDescriptorTests.m \ + objectivec/Tests/GPBDictionaryTests+Bool.m \ + objectivec/Tests/GPBDictionaryTests+Int32.m \ + objectivec/Tests/GPBDictionaryTests+Int64.m \ + objectivec/Tests/GPBDictionaryTests+String.m \ + objectivec/Tests/GPBDictionaryTests+UInt32.m \ + objectivec/Tests/GPBDictionaryTests+UInt64.m \ + objectivec/Tests/GPBDictionaryTests.pddm \ + objectivec/Tests/GPBFilteredMessageTests.m \ + objectivec/Tests/GPBMessageTests+Merge.m \ + objectivec/Tests/GPBMessageTests+Runtime.m \ + objectivec/Tests/GPBMessageTests+Serialization.m \ + objectivec/Tests/GPBMessageTests.m \ + objectivec/Tests/GPBPerfTests.m \ + objectivec/Tests/GPBStringTests.m \ + objectivec/Tests/GPBSwiftTests.swift \ + objectivec/Tests/GPBTestUtilities.h \ + objectivec/Tests/GPBTestUtilities.m \ + objectivec/Tests/GPBUnittestProtos.m \ + objectivec/Tests/GPBUnknownFieldSetTest.m \ + objectivec/Tests/GPBUtilitiesTests.m \ + objectivec/Tests/GPBWellKnownTypesTest.m \ + objectivec/Tests/GPBWireFormatTests.m \ + objectivec/Tests/iOSTestHarness/AppDelegate.m \ + objectivec/Tests/iOSTestHarness/en.lproj/InfoPlist.strings \ + objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/Contents.json \ + objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6.png \ + objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6@2x.png \ + objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7.png \ + objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7@2x.png \ + objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6.png \ + objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6@2x.png \ + objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7@2x.png \ + objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7@3x.png \ + objectivec/Tests/iOSTestHarness/Images.xcassets/LaunchImage.launchimage/Contents.json \ + objectivec/Tests/iOSTestHarness/Info.plist \ + objectivec/Tests/iOSTestHarness/LaunchScreen.xib \ + objectivec/Tests/text_format_map_unittest_data.txt \ + objectivec/Tests/text_format_unittest_data.txt \ + objectivec/Tests/unittest_cycle.proto \ + objectivec/Tests/unittest_filter.proto \ + objectivec/Tests/unittest_name_mangling.proto \ + objectivec/Tests/unittest_objc.proto \ + objectivec/Tests/unittest_runtime_proto2.proto \ + objectivec/Tests/unittest_runtime_proto3.proto \ + objectivec/Tests/UnitTests-Bridging-Header.h \ + objectivec/Tests/UnitTests-Info.plist python_EXTRA_DIST= \ python/google/protobuf/internal/api_implementation.cc \ @@ -301,7 +423,7 @@ ruby_EXTRA_DIST= \ ruby/tests/generated_code.rb \ ruby/tests/generated_code_test.rb -all_EXTRA_DIST=$(java_EXTRA_DIST) $(javanano_EXTRA_DIST) $(python_EXTRA_DIST) $(ruby_EXTRA_DIST) +all_EXTRA_DIST=$(java_EXTRA_DIST) $(javanano_EXTRA_DIST) $(objectivec_EXTRA_DIST) $(python_EXTRA_DIST) $(ruby_EXTRA_DIST) EXTRA_DIST = $(@DIST_LANG@_EXTRA_DIST) \ autogen.sh \ diff --git a/conformance/ConformanceJava.java b/conformance/ConformanceJava.java new file mode 100644 index 00000000..c1a53141 --- /dev/null +++ b/conformance/ConformanceJava.java @@ -0,0 +1,120 @@ + +import com.google.protobuf.conformance.Conformance; +import com.google.protobuf.InvalidProtocolBufferException; + +class ConformanceJava { + private int testCount = 0; + + private boolean readFromStdin(byte[] buf, int len) throws Exception { + int ofs = 0; + while (len > 0) { + int read = System.in.read(buf, ofs, len); + if (read == -1) { + return false; // EOF + } + ofs += read; + len -= read; + } + + return true; + } + + private void writeToStdout(byte[] buf) throws Exception { + System.out.write(buf); + } + + // Returns -1 on EOF (the actual values will always be positive). + private int readLittleEndianIntFromStdin() throws Exception { + byte[] buf = new byte[4]; + if (!readFromStdin(buf, 4)) { + return -1; + } + return buf[0] | (buf[1] << 1) | (buf[2] << 2) | (buf[3] << 3); + } + + private void writeLittleEndianIntToStdout(int val) throws Exception { + byte[] buf = new byte[4]; + buf[0] = (byte)val; + buf[1] = (byte)(val >> 8); + buf[2] = (byte)(val >> 16); + buf[3] = (byte)(val >> 24); + writeToStdout(buf); + } + + private Conformance.ConformanceResponse doTest(Conformance.ConformanceRequest request) { + Conformance.TestAllTypes testMessage; + + switch (request.getPayloadCase()) { + case PROTOBUF_PAYLOAD: { + try { + testMessage = Conformance.TestAllTypes.parseFrom(request.getProtobufPayload()); + } catch (InvalidProtocolBufferException e) { + return Conformance.ConformanceResponse.newBuilder().setParseError(e.getMessage()).build(); + } + break; + } + case JSON_PAYLOAD: { + return Conformance.ConformanceResponse.newBuilder().setRuntimeError("JSON not yet supported.").build(); + } + case PAYLOAD_NOT_SET: { + throw new RuntimeException("Request didn't have payload."); + } + + default: { + throw new RuntimeException("Unexpected payload case."); + } + } + + switch (request.getRequestedOutput()) { + case UNSPECIFIED: + throw new RuntimeException("Unspecified output format."); + + case PROTOBUF: + return Conformance.ConformanceResponse.newBuilder().setProtobufPayload(testMessage.toByteString()).build(); + + case JSON: + return Conformance.ConformanceResponse.newBuilder().setRuntimeError("JSON not yet supported.").build(); + + default: { + throw new RuntimeException("Unexpected request output."); + } + } + } + + private boolean doTestIo() throws Exception { + int bytes = readLittleEndianIntFromStdin(); + + if (bytes == -1) { + return false; // EOF + } + + byte[] serializedInput = new byte[bytes]; + + if (!readFromStdin(serializedInput, bytes)) { + throw new RuntimeException("Unexpected EOF from test program."); + } + + Conformance.ConformanceRequest request = + Conformance.ConformanceRequest.parseFrom(serializedInput); + Conformance.ConformanceResponse response = doTest(request); + byte[] serializedOutput = response.toByteArray(); + + writeLittleEndianIntToStdout(serializedOutput.length); + writeToStdout(serializedOutput); + + return true; + } + + public void run() throws Exception { + while (doTestIo()) { + // Empty. + } + + System.err.println("ConformanceJava: received EOF from test runner after " + + this.testCount + " tests"); + } + + public static void main(String[] args) throws Exception { + new ConformanceJava().run(); + } +} diff --git a/conformance/Makefile.am b/conformance/Makefile.am index 0c4eae75..95343f14 100644 --- a/conformance/Makefile.am +++ b/conformance/Makefile.am @@ -21,30 +21,43 @@ conformance_cpp_CPPFLAGS = -I$(top_srcdir)/src if USE_EXTERNAL_PROTOC -unittest_proto_middleman: $(protoc_inputs) - $(PROTOC) -I$(srcdir) --cpp_out=. $^ - touch unittest_proto_middleman +protoc_middleman: $(protoc_inputs) + $(PROTOC) -I$(srcdir) --cpp_out=. --java_out=. $^ + touch protoc_middleman else # We have to cd to $(srcdir) before executing protoc because $(protoc_inputs) is # relative to srcdir, which may not be the same as the current directory when # building out-of-tree. -unittest_proto_middleman: $(top_srcdir)/src/protoc$(EXEEXT) $(protoc_inputs) - oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. --cpp_out=$$oldpwd $(protoc_inputs) ) - touch unittest_proto_middleman +protoc_middleman: $(top_srcdir)/src/protoc$(EXEEXT) $(protoc_inputs) + oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. --cpp_out=$$oldpwd --java_out=$$oldpwd $(protoc_inputs) ) + touch protoc_middleman endif -$(protoc_outputs): unittest_proto_middleman +$(protoc_outputs): protoc_middleman BUILT_SOURCES = $(protoc_outputs) -CLEANFILES = $(protoc_outputs) unittest_proto_middleman +CLEANFILES = $(protoc_outputs) protoc_middleman javac_middleman conformance-java MAINTAINERCLEANFILES = \ Makefile.in +javac_middleman: ConformanceJava.java protoc_middleman + javac -classpath ../java/target/classes ConformanceJava.java com/google/protobuf/conformance/Conformance.java + @touch javac_middleman + +conformance-java: javac_middleman + @echo "Writing shortcut script conformance-java..." + @echo '#! /bin/sh' > conformance-java + @echo 'java -classpath .:../java/target/classes ConformanceJava "$$@"' >> conformance-java + @chmod +x conformance-java + # Targets for actually running tests. -test_cpp: unittest_proto_middleman conformance-test-runner conformance-cpp +test_cpp: protoc_middleman conformance-test-runner conformance-cpp ./conformance-test-runner ./conformance-cpp + +test_java: protoc_middleman conformance-test-runner conformance-java + ./conformance-test-runner ./conformance-java diff --git a/conformance/conformance.proto b/conformance/conformance.proto index 0fb66cf9..7b676898 100644 --- a/conformance/conformance.proto +++ b/conformance/conformance.proto @@ -30,6 +30,7 @@ syntax = "proto3"; package conformance; +option java_package = "com.google.protobuf.conformance"; // This defines the conformance testing protocol. This protocol exists between // the conformance test suite itself and the code being tested. For each test, diff --git a/conformance/conformance_test_runner.cc b/conformance/conformance_test_runner.cc index 21277700..ca5877bd 100644 --- a/conformance/conformance_test_runner.cc +++ b/conformance/conformance_test_runner.cc @@ -48,9 +48,9 @@ // Every test consists of a ConformanceRequest/ConformanceResponse // request/reply pair. The protocol on the pipe is simply: // -// 1. tester sends 4-byte length N +// 1. tester sends 4-byte length N (little endian) // 2. tester sends N bytes representing a ConformanceRequest proto -// 3. testee sends 4-byte length M +// 3. testee sends 4-byte length M (little endian) // 4. testee sends M bytes representing a ConformanceResponse proto #include <errno.h> diff --git a/examples/add_person.py b/examples/add_person.py index 78e56966..5a7b968e 100755 --- a/examples/add_person.py +++ b/examples/add_person.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/env python # See README.txt for information and build instructions. diff --git a/examples/list_people.py b/examples/list_people.py index f9f36b96..d470349a 100755 --- a/examples/list_people.py +++ b/examples/list_people.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/env python # See README.txt for information and build instructions. diff --git a/generate_descriptor_proto.sh b/generate_descriptor_proto.sh index b25a3c6a..2dad36ab 100755 --- a/generate_descriptor_proto.sh +++ b/generate_descriptor_proto.sh @@ -27,6 +27,7 @@ __EOF__ fi cd src +make $@ google/protobuf/stubs/pbconfig.h CORE_PROTO_IS_CORRECT=0 while [ $CORE_PROTO_IS_CORRECT -ne 1 ] do diff --git a/javanano/README.md b/javanano/README.md index 7d696aa7..e19b90b1 100644 --- a/javanano/README.md +++ b/javanano/README.md @@ -145,6 +145,7 @@ optional_field_style -> default or accessors enum_style -> c or java ignore_services -> true or false parcelable_messages -> true or false +generate_intdefs -> true or false ``` **java_package=\<file-name\>|\<package-name\>** (no default) @@ -302,6 +303,28 @@ parcelable_messages -> true or false Android-specific option to generate Parcelable messages. +**generate_intdefs={true,false}** (default: false) + Android-specific option to generate @IntDef annotations for enums. + + If turned on, an '@IntDef' annotation (a public @interface) will be + generated for each enum, and every integer parameter and return + value in the generated code meant for this enum will be annotated + with it. This interface is generated with the same name and at the + same place as the enum members' container interfaces described + above under 'enum_style=java', regardless of the enum_style option + used. When this is combined with enum_style=java, the interface + will be both the '@IntDef' annotation and the container of the enum + members; otherwise the interface has an empty body. + + Your app must declare a compile-time dependency on the + android-support-annotations library. + + For more information on how these @IntDef annotations help with + compile-time type safety, see: + https://sites.google.com/a/android.com/tools/tech-docs/support-annotations + and + https://developer.android.com/reference/android/support/annotation/IntDef.html + To use nano protobufs within the Android repo: ---------------------------------------------- diff --git a/javanano/pom.xml b/javanano/pom.xml index 7a2be9df..3d8cfb9f 100644 --- a/javanano/pom.xml +++ b/javanano/pom.xml @@ -97,19 +97,19 @@ <arg value="src/test/java/com/google/protobuf/nano/map_test.proto" /> </exec> <exec executable="../src/protoc"> - <arg value="--javanano_out=store_unknown_fields=true,generate_equals=true:target/generated-test-sources" /> + <arg value="--javanano_out=store_unknown_fields=true,generate_equals=true,generate_clone=true:target/generated-test-sources" /> <arg value="--proto_path=src/test/java/com" /> <arg value="src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto" /> <arg value="src/test/java/com/google/protobuf/nano/unittest_extension_singular_nano.proto" /> <arg value="src/test/java/com/google/protobuf/nano/unittest_extension_repeated_nano.proto" /> </exec> <exec executable="../src/protoc"> - <arg value="--javanano_out=store_unknown_fields=true:target/generated-test-sources" /> + <arg value="--javanano_out=store_unknown_fields=true,generate_clone=true:target/generated-test-sources" /> <arg value="--proto_path=src/test/java/com" /> <arg value="src/test/java/com/google/protobuf/nano/unittest_extension_packed_nano.proto" /> </exec> <exec executable="../src/protoc"> - <arg value="--javanano_out=java_nano_generate_has=true,generate_equals=true:target/generated-test-sources" /> + <arg value="--javanano_out=java_nano_generate_has=true,generate_equals=true,generate_clone=true:target/generated-test-sources" /> <arg value="--proto_path=src/test/java/com" /> <arg value="src/test/java/com/google/protobuf/nano/unittest_has_nano.proto" /> </exec> @@ -139,6 +139,15 @@ <arg value="--proto_path=src/test/java/com" /> <arg value="src/test/java/com/google/protobuf/nano/unittest_reference_types_nano.proto" /> </exec> + <exec executable="../src/protoc"> + <arg value="--javanano_out= + optional_field_style=reftypes_compat_mode, + generate_equals=true, + java_outer_classname=google/protobuf/nano/unittest_reference_types_nano.proto|NanoReferenceTypesCompat + :target/generated-test-sources" /> + <arg value="--proto_path=src/test/java/com" /> + <arg value="src/test/java/com/google/protobuf/nano/unittest_reference_types_nano.proto" /> + </exec> </tasks> <testSourceRoot>target/generated-test-sources</testSourceRoot> </configuration> diff --git a/javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java b/javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java index 4b45c6d2..f3993155 100644 --- a/javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java +++ b/javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java @@ -236,6 +236,8 @@ public final class CodedInputByteBufferNano { System.arraycopy(buffer, bufferPos, result, 0, size); bufferPos += size; return result; + } else if (size == 0) { + return WireFormatNano.EMPTY_BYTES; } else { // Slow path: Build a byte array first then copy it. return readRawBytes(size); diff --git a/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java b/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java index 35907183..b1b0c53a 100644 --- a/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java +++ b/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java @@ -31,6 +31,9 @@ package com.google.protobuf.nano; import java.io.IOException; +import java.nio.BufferOverflowException; +import java.nio.ByteBuffer; +import java.nio.ReadOnlyBufferException; /** * Encodes and writes protocol message fields. @@ -47,15 +50,17 @@ import java.io.IOException; * @author kneton@google.com Kenton Varda */ public final class CodedOutputByteBufferNano { - private final byte[] buffer; - private final int limit; - private int position; + /* max bytes per java UTF-16 char in UTF-8 */ + private static final int MAX_UTF8_EXPANSION = 3; + private final ByteBuffer buffer; private CodedOutputByteBufferNano(final byte[] buffer, final int offset, final int length) { + this(ByteBuffer.wrap(buffer, offset, length)); + } + + private CodedOutputByteBufferNano(final ByteBuffer buffer) { this.buffer = buffer; - position = offset; - limit = offset + length; } /** @@ -287,14 +292,213 @@ public final class CodedOutputByteBufferNano { /** Write a {@code string} field to the stream. */ public void writeStringNoTag(final String value) throws IOException { - // Unfortunately there does not appear to be any way to tell Java to encode - // UTF-8 directly into our buffer, so we have to let it create its own byte - // array and then copy. - final byte[] bytes = value.getBytes(InternalNano.UTF_8); - writeRawVarint32(bytes.length); - writeRawBytes(bytes); + // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()), + // and at most 3 times of it. Optimize for the case where we know this length results in a + // constant varint length - saves measuring length of the string. + try { + final int minLengthVarIntSize = computeRawVarint32Size(value.length()); + final int maxLengthVarIntSize = computeRawVarint32Size(value.length() * MAX_UTF8_EXPANSION); + if (minLengthVarIntSize == maxLengthVarIntSize) { + int oldPosition = buffer.position(); + // Buffer.position, when passed a position that is past its limit, throws + // IllegalArgumentException, and this class is documented to throw + // OutOfSpaceException instead. + if (buffer.remaining() < minLengthVarIntSize) { + throw new OutOfSpaceException(oldPosition + minLengthVarIntSize, buffer.limit()); + } + buffer.position(oldPosition + minLengthVarIntSize); + encode(value, buffer); + int newPosition = buffer.position(); + buffer.position(oldPosition); + writeRawVarint32(newPosition - oldPosition - minLengthVarIntSize); + buffer.position(newPosition); + } else { + writeRawVarint32(encodedLength(value)); + encode(value, buffer); + } + } catch (BufferOverflowException e) { + final OutOfSpaceException outOfSpaceException = new OutOfSpaceException(buffer.position(), + buffer.limit()); + outOfSpaceException.initCause(e); + throw outOfSpaceException; + } + } + + // These UTF-8 handling methods are copied from Guava's Utf8 class. + /** + * Returns the number of bytes in the UTF-8-encoded form of {@code sequence}. For a string, + * this method is equivalent to {@code string.getBytes(UTF_8).length}, but is more efficient in + * both time and space. + * + * @throws IllegalArgumentException if {@code sequence} contains ill-formed UTF-16 (unpaired + * surrogates) + */ + private static int encodedLength(CharSequence sequence) { + // Warning to maintainers: this implementation is highly optimized. + int utf16Length = sequence.length(); + int utf8Length = utf16Length; + int i = 0; + + // This loop optimizes for pure ASCII. + while (i < utf16Length && sequence.charAt(i) < 0x80) { + i++; + } + + // This loop optimizes for chars less than 0x800. + for (; i < utf16Length; i++) { + char c = sequence.charAt(i); + if (c < 0x800) { + utf8Length += ((0x7f - c) >>> 31); // branch free! + } else { + utf8Length += encodedLengthGeneral(sequence, i); + break; + } + } + + if (utf8Length < utf16Length) { + // Necessary and sufficient condition for overflow because of maximum 3x expansion + throw new IllegalArgumentException("UTF-8 length does not fit in int: " + + (utf8Length + (1L << 32))); + } + return utf8Length; + } + + private static int encodedLengthGeneral(CharSequence sequence, int start) { + int utf16Length = sequence.length(); + int utf8Length = 0; + for (int i = start; i < utf16Length; i++) { + char c = sequence.charAt(i); + if (c < 0x800) { + utf8Length += (0x7f - c) >>> 31; // branch free! + } else { + utf8Length += 2; + // jdk7+: if (Character.isSurrogate(c)) { + if (Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE) { + // Check that we have a well-formed surrogate pair. + int cp = Character.codePointAt(sequence, i); + if (cp < Character.MIN_SUPPLEMENTARY_CODE_POINT) { + throw new IllegalArgumentException("Unpaired surrogate at index " + i); + } + i++; + } + } + } + return utf8Length; } + /** + * Encodes {@code sequence} into UTF-8, in {@code byteBuffer}. For a string, this method is + * equivalent to {@code buffer.put(string.getBytes(UTF_8))}, but is more efficient in both time + * and space. Bytes are written starting at the current position. This method requires paired + * surrogates, and therefore does not support chunking. + * + * <p>To ensure sufficient space in the output buffer, either call {@link #encodedLength} to + * compute the exact amount needed, or leave room for {@code 3 * sequence.length()}, which is the + * largest possible number of bytes that any input can be encoded to. + * + * @throws IllegalArgumentException if {@code sequence} contains ill-formed UTF-16 (unpaired + * surrogates) + * @throws BufferOverflowException if {@code sequence} encoded in UTF-8 does not fit in + * {@code byteBuffer}'s remaining space. + * @throws ReadOnlyBufferException if {@code byteBuffer} is a read-only buffer. + */ + private static void encode(CharSequence sequence, ByteBuffer byteBuffer) { + if (byteBuffer.isReadOnly()) { + throw new ReadOnlyBufferException(); + } else if (byteBuffer.hasArray()) { + try { + int encoded = encode(sequence, + byteBuffer.array(), + byteBuffer.arrayOffset() + byteBuffer.position(), + byteBuffer.remaining()); + byteBuffer.position(encoded - byteBuffer.arrayOffset()); + } catch (ArrayIndexOutOfBoundsException e) { + BufferOverflowException boe = new BufferOverflowException(); + boe.initCause(e); + throw boe; + } + } else { + encodeDirect(sequence, byteBuffer); + } + } + + private static void encodeDirect(CharSequence sequence, ByteBuffer byteBuffer) { + int utf16Length = sequence.length(); + for (int i = 0; i < utf16Length; i++) { + final char c = sequence.charAt(i); + if (c < 0x80) { // ASCII + byteBuffer.put((byte) c); + } else if (c < 0x800) { // 11 bits, two UTF-8 bytes + byteBuffer.put((byte) ((0xF << 6) | (c >>> 6))); + byteBuffer.put((byte) (0x80 | (0x3F & c))); + } else if (c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) { + // Maximium single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes + byteBuffer.put((byte) ((0xF << 5) | (c >>> 12))); + byteBuffer.put((byte) (0x80 | (0x3F & (c >>> 6)))); + byteBuffer.put((byte) (0x80 | (0x3F & c))); + } else { + final char low; + if (i + 1 == sequence.length() + || !Character.isSurrogatePair(c, (low = sequence.charAt(++i)))) { + throw new IllegalArgumentException("Unpaired surrogate at index " + (i - 1)); + } + int codePoint = Character.toCodePoint(c, low); + byteBuffer.put((byte) ((0xF << 4) | (codePoint >>> 18))); + byteBuffer.put((byte) (0x80 | (0x3F & (codePoint >>> 12)))); + byteBuffer.put((byte) (0x80 | (0x3F & (codePoint >>> 6)))); + byteBuffer.put((byte) (0x80 | (0x3F & codePoint))); + } + } + } + + private static int encode(CharSequence sequence, byte[] bytes, int offset, int length) { + int utf16Length = sequence.length(); + int j = offset; + int i = 0; + int limit = offset + length; + // Designed to take advantage of + // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination + for (char c; i < utf16Length && i + j < limit && (c = sequence.charAt(i)) < 0x80; i++) { + bytes[j + i] = (byte) c; + } + if (i == utf16Length) { + return j + utf16Length; + } + j += i; + for (char c; i < utf16Length; i++) { + c = sequence.charAt(i); + if (c < 0x80 && j < limit) { + bytes[j++] = (byte) c; + } else if (c < 0x800 && j <= limit - 2) { // 11 bits, two UTF-8 bytes + bytes[j++] = (byte) ((0xF << 6) | (c >>> 6)); + bytes[j++] = (byte) (0x80 | (0x3F & c)); + } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) && j <= limit - 3) { + // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes + bytes[j++] = (byte) ((0xF << 5) | (c >>> 12)); + bytes[j++] = (byte) (0x80 | (0x3F & (c >>> 6))); + bytes[j++] = (byte) (0x80 | (0x3F & c)); + } else if (j <= limit - 4) { + // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8 bytes + final char low; + if (i + 1 == sequence.length() + || !Character.isSurrogatePair(c, (low = sequence.charAt(++i)))) { + throw new IllegalArgumentException("Unpaired surrogate at index " + (i - 1)); + } + int codePoint = Character.toCodePoint(c, low); + bytes[j++] = (byte) ((0xF << 4) | (codePoint >>> 18)); + bytes[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 12))); + bytes[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 6))); + bytes[j++] = (byte) (0x80 | (0x3F & codePoint)); + } else { + throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + j); + } + } + return j; + } + + // End guava UTF-8 methods + + /** Write a {@code group} field to the stream. */ public void writeGroupNoTag(final MessageNano value) throws IOException { value.writeTo(this); @@ -602,9 +806,8 @@ public final class CodedOutputByteBufferNano { * {@code string} field. */ public static int computeStringSizeNoTag(final String value) { - final byte[] bytes = value.getBytes(InternalNano.UTF_8); - return computeRawVarint32Size(bytes.length) + - bytes.length; + final int length = encodedLength(value); + return computeRawVarint32Size(length) + length; } /** @@ -687,7 +890,7 @@ public final class CodedOutputByteBufferNano { * Otherwise, throws {@code UnsupportedOperationException}. */ public int spaceLeft() { - return limit - position; + return buffer.remaining(); } /** @@ -705,6 +908,23 @@ public final class CodedOutputByteBufferNano { } /** + * Returns the position within the internal buffer. + */ + public int position() { + return buffer.position(); + } + + /** + * Resets the position within the internal buffer to zero. + * + * @see #position + * @see #spaceLeft + */ + public void reset() { + buffer.clear(); + } + + /** * If you create a CodedOutputStream around a simple flat array, you must * not attempt to write more bytes than the array has space. Otherwise, * this exception will be thrown. @@ -720,12 +940,12 @@ public final class CodedOutputByteBufferNano { /** Write a single byte. */ public void writeRawByte(final byte value) throws IOException { - if (position == limit) { + if (!buffer.hasRemaining()) { // We're writing to a single buffer. - throw new OutOfSpaceException(position, limit); + throw new OutOfSpaceException(buffer.position(), buffer.limit()); } - buffer[position++] = value; + buffer.put(value); } /** Write a single byte, represented by an integer value. */ @@ -741,13 +961,11 @@ public final class CodedOutputByteBufferNano { /** Write part of an array of bytes. */ public void writeRawBytes(final byte[] value, int offset, int length) throws IOException { - if (limit - position >= length) { - // We have room in the current buffer. - System.arraycopy(value, offset, buffer, position, length); - position += length; + if (buffer.remaining() >= length) { + buffer.put(value, offset, length); } else { // We're writing to a single buffer. - throw new OutOfSpaceException(position, limit); + throw new OutOfSpaceException(buffer.position(), buffer.limit()); } } diff --git a/javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java b/javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java index b979390d..87973d76 100644 --- a/javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java +++ b/javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java @@ -160,28 +160,10 @@ public abstract class ExtendableMessageNano<M extends ExtendableMessageNano<M>> return true; } - /** - * Returns whether the stored unknown field data in this message is equivalent to that in the - * other message. - * - * @param other the other message. - * @return whether the two sets of unknown field data are equal. - */ - protected final boolean unknownFieldDataEquals(M other) { - if (unknownFieldData == null || unknownFieldData.isEmpty()) { - return other.unknownFieldData == null || other.unknownFieldData.isEmpty(); - } else { - return unknownFieldData.equals(other.unknownFieldData); - } - } - - /** - * Computes the hashcode representing the unknown field data stored in this message. - * - * @return the hashcode for the unknown field data. - */ - protected final int unknownFieldDataHashCode() { - return (unknownFieldData == null || unknownFieldData.isEmpty() - ? 0 : unknownFieldData.hashCode()); + @Override + public M clone() throws CloneNotSupportedException { + M cloned = (M) super.clone(); + InternalNano.cloneUnknownFieldData(this, cloned); + return cloned; } } diff --git a/javanano/src/main/java/com/google/protobuf/nano/Extension.java b/javanano/src/main/java/com/google/protobuf/nano/Extension.java index c29b030f..c458f9b1 100644 --- a/javanano/src/main/java/com/google/protobuf/nano/Extension.java +++ b/javanano/src/main/java/com/google/protobuf/nano/Extension.java @@ -79,12 +79,30 @@ public class Extension<M extends ExtendableMessageNano<M>, T> { * Should be used by the generated code only. * * @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP} + * @deprecated use {@link #createMessageTyped(int, Class, long)} instead. */ + @Deprecated public static <M extends ExtendableMessageNano<M>, T extends MessageNano> Extension<M, T> createMessageTyped(int type, Class<T> clazz, int tag) { return new Extension<M, T>(type, clazz, tag, false); } + // Note: these create...() methods take a long for the tag parameter, + // because tags are represented as unsigned ints, and these values exist + // in generated code as long values. However, they can fit in 32-bits, so + // it's safe to cast them to int without loss of precision. + + /** + * Creates an {@code Extension} of the given message type and tag number. + * Should be used by the generated code only. + * + * @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP} + */ + public static <M extends ExtendableMessageNano<M>, T extends MessageNano> + Extension<M, T> createMessageTyped(int type, Class<T> clazz, long tag) { + return new Extension<M, T>(type, clazz, (int) tag, false); + } + /** * Creates a repeated {@code Extension} of the given message type and tag number. * Should be used by the generated code only. @@ -92,8 +110,8 @@ public class Extension<M extends ExtendableMessageNano<M>, T> { * @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP} */ public static <M extends ExtendableMessageNano<M>, T extends MessageNano> - Extension<M, T[]> createRepeatedMessageTyped(int type, Class<T[]> clazz, int tag) { - return new Extension<M, T[]>(type, clazz, tag, true); + Extension<M, T[]> createRepeatedMessageTyped(int type, Class<T[]> clazz, long tag) { + return new Extension<M, T[]>(type, clazz, (int) tag, true); } /** @@ -104,8 +122,8 @@ public class Extension<M extends ExtendableMessageNano<M>, T> { * @param clazz the boxed Java type of this extension */ public static <M extends ExtendableMessageNano<M>, T> - Extension<M, T> createPrimitiveTyped(int type, Class<T> clazz, int tag) { - return new PrimitiveExtension<M, T>(type, clazz, tag, false, 0, 0); + Extension<M, T> createPrimitiveTyped(int type, Class<T> clazz, long tag) { + return new PrimitiveExtension<M, T>(type, clazz, (int) tag, false, 0, 0); } /** @@ -117,8 +135,9 @@ public class Extension<M extends ExtendableMessageNano<M>, T> { */ public static <M extends ExtendableMessageNano<M>, T> Extension<M, T> createRepeatedPrimitiveTyped( - int type, Class<T> clazz, int tag, int nonPackedTag, int packedTag) { - return new PrimitiveExtension<M, T>(type, clazz, tag, true, nonPackedTag, packedTag); + int type, Class<T> clazz, long tag, long nonPackedTag, long packedTag) { + return new PrimitiveExtension<M, T>(type, clazz, (int) tag, true, + (int) nonPackedTag, (int) packedTag); } /** @@ -136,7 +155,7 @@ public class Extension<M extends ExtendableMessageNano<M>, T> { protected final Class<T> clazz; /** - * Tag number of this extension. + * Tag number of this extension. The data should be viewed as an unsigned 32-bit value. */ public final int tag; diff --git a/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java b/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java index cdb66da2..eca9c0d9 100644 --- a/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java +++ b/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java @@ -35,9 +35,12 @@ package com.google.protobuf.nano; * A custom version of {@link android.util.SparseArray} with the minimal API * for storing {@link FieldData} objects. * + * <p>This class is an internal implementation detail of nano and should not + * be called directly by clients. + * * Based on {@link android.support.v4.util.SpareArrayCompat}. */ -class FieldArray { +public final class FieldArray implements Cloneable { private static final FieldData DELETED = new FieldData(); private boolean mGarbage = false; @@ -48,7 +51,7 @@ class FieldArray { /** * Creates a new FieldArray containing no fields. */ - public FieldArray() { + FieldArray() { this(10); } @@ -57,7 +60,7 @@ class FieldArray { * require any additional memory allocation to store the specified * number of mappings. */ - public FieldArray(int initialCapacity) { + FieldArray(int initialCapacity) { initialCapacity = idealIntArraySize(initialCapacity); mFieldNumbers = new int[initialCapacity]; mData = new FieldData[initialCapacity]; @@ -68,7 +71,7 @@ class FieldArray { * Gets the FieldData mapped from the specified fieldNumber, or <code>null</code> * if no such mapping has been made. */ - public FieldData get(int fieldNumber) { + FieldData get(int fieldNumber) { int i = binarySearch(fieldNumber); if (i < 0 || mData[i] == DELETED) { @@ -81,7 +84,7 @@ class FieldArray { /** * Removes the data from the specified fieldNumber, if there was any. */ - public void remove(int fieldNumber) { + void remove(int fieldNumber) { int i = binarySearch(fieldNumber); if (i >= 0 && mData[i] != DELETED) { @@ -118,7 +121,7 @@ class FieldArray { * 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) { + void put(int fieldNumber, FieldData data) { int i = binarySearch(fieldNumber); if (i >= 0) { @@ -167,7 +170,7 @@ class FieldArray { * Returns the number of key-value mappings that this FieldArray * currently stores. */ - public int size() { + int size() { if (mGarbage) { gc(); } @@ -184,7 +187,7 @@ class FieldArray { * the value from the <code>index</code>th key-value mapping that this * FieldArray stores. */ - public FieldData dataAt(int index) { + FieldData dataAt(int index) { if (mGarbage) { gc(); } @@ -270,4 +273,19 @@ class FieldArray { } return true; } + + @Override + public final FieldArray clone() { + // Trigger GC so we compact and don't copy DELETED elements. + int size = size(); + FieldArray clone = new FieldArray(size); + System.arraycopy(mFieldNumbers, 0, clone.mFieldNumbers, 0, size); + for (int i = 0; i < size; i++) { + if (mData[i] != null) { + clone.mData[i] = mData[i].clone(); + } + } + clone.mSize = size; + return clone; + } } diff --git a/javanano/src/main/java/com/google/protobuf/nano/FieldData.java b/javanano/src/main/java/com/google/protobuf/nano/FieldData.java index 21ead88b..ebebabc8 100644 --- a/javanano/src/main/java/com/google/protobuf/nano/FieldData.java +++ b/javanano/src/main/java/com/google/protobuf/nano/FieldData.java @@ -39,7 +39,7 @@ import java.util.List; * Stores unknown fields. These might be extensions or fields that the generated API doesn't * know about yet. */ -class FieldData { +class FieldData implements Cloneable { private Extension<?, ?> cachedExtension; private Object value; /** The serialised values for this object. Will be cleared if getValue is called */ @@ -187,4 +187,54 @@ class FieldData { return result; } + @Override + public final FieldData clone() { + FieldData clone = new FieldData(); + try { + clone.cachedExtension = cachedExtension; + if (unknownFieldData == null) { + clone.unknownFieldData = null; + } else { + clone.unknownFieldData.addAll(unknownFieldData); + } + + // Whether we need to deep clone value depends on its type. Primitive reference types + // (e.g. Integer, Long etc.) are ok, since they're immutable. We need to clone arrays + // and messages. + if (value == null) { + // No cloning required. + } else if (value instanceof MessageNano) { + clone.value = ((MessageNano) value).clone(); + } else if (value instanceof byte[]) { + clone.value = ((byte[]) value).clone(); + } else if (value instanceof byte[][]) { + byte[][] valueArray = (byte[][]) value; + byte[][] cloneArray = new byte[valueArray.length][]; + clone.value = cloneArray; + for (int i = 0; i < valueArray.length; i++) { + cloneArray[i] = valueArray[i].clone(); + } + } else if (value instanceof boolean[]) { + clone.value = ((boolean[]) value).clone(); + } else if (value instanceof int[]) { + clone.value = ((int[]) value).clone(); + } else if (value instanceof long[]) { + clone.value = ((long[]) value).clone(); + } else if (value instanceof float[]) { + clone.value = ((float[]) value).clone(); + } else if (value instanceof double[]) { + clone.value = ((double[]) value).clone(); + } else if (value instanceof MessageNano[]) { + MessageNano[] valueArray = (MessageNano[]) value; + MessageNano[] cloneArray = new MessageNano[valueArray.length]; + clone.value = cloneArray; + for (int i = 0; i < valueArray.length; i++) { + cloneArray[i] = valueArray[i].clone(); + } + } + return clone; + } catch (CloneNotSupportedException e) { + throw new AssertionError(e); + } + } } diff --git a/javanano/src/main/java/com/google/protobuf/nano/InternalNano.java b/javanano/src/main/java/com/google/protobuf/nano/InternalNano.java index e7ba8d12..f1263df5 100644 --- a/javanano/src/main/java/com/google/protobuf/nano/InternalNano.java +++ b/javanano/src/main/java/com/google/protobuf/nano/InternalNano.java @@ -536,4 +536,12 @@ public final class InternalNano { } return o.hashCode(); } + + // This avoids having to make FieldArray public. + public static void cloneUnknownFieldData(ExtendableMessageNano original, + ExtendableMessageNano cloned) { + if (original.unknownFieldData != null) { + cloned.unknownFieldData = (FieldArray) original.unknownFieldData.clone(); + } + } } diff --git a/javanano/src/main/java/com/google/protobuf/nano/MessageNano.java b/javanano/src/main/java/com/google/protobuf/nano/MessageNano.java index 81e58571..23475027 100644 --- a/javanano/src/main/java/com/google/protobuf/nano/MessageNano.java +++ b/javanano/src/main/java/com/google/protobuf/nano/MessageNano.java @@ -187,4 +187,12 @@ public abstract class MessageNano { public String toString() { return MessageNanoPrinter.print(this); } + + /** + * Provides support for cloning. This only works if you specify the generate_clone method. + */ + @Override + public MessageNano clone() throws CloneNotSupportedException { + return (MessageNano) super.clone(); + } } diff --git a/javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java b/javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java index c4b2ad3d..d9500bb9 100644 --- a/javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java +++ b/javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java @@ -109,6 +109,10 @@ public final class MessageNanoPrinter { for (Field field : clazz.getFields()) { int modifiers = field.getModifiers(); String fieldName = field.getName(); + if ("cachedSize".equals(fieldName)) { + // TODO(bduff): perhaps cachedSize should have a more obscure name. + continue; + } if ((modifiers & Modifier.PUBLIC) == Modifier.PUBLIC && (modifiers & Modifier.STATIC) != Modifier.STATIC diff --git a/javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java b/javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java index a17fccf3..b1678d1b 100644 --- a/javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java +++ b/javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java @@ -42,6 +42,10 @@ import java.util.Arrays; final class UnknownFieldData { final int tag; + /** + * Important: this should be treated as immutable, even though it's possible + * to change the array values. + */ final byte[] bytes; UnknownFieldData(int tag, byte[] bytes) { diff --git a/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java b/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java index 7de84310..3a75777a 100644 --- a/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java +++ b/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java @@ -31,11 +31,13 @@ package com.google.protobuf.nano; import com.google.protobuf.nano.MapTestProto.TestMap; +import com.google.protobuf.nano.CodedOutputByteBufferNano; import com.google.protobuf.nano.MapTestProto.TestMap.MessageValue; import com.google.protobuf.nano.NanoAccessorsOuterClass.TestNanoAccessors; import com.google.protobuf.nano.NanoHasOuterClass.TestAllTypesNanoHas; import com.google.protobuf.nano.NanoOuterClass.TestAllTypesNano; import com.google.protobuf.nano.UnittestRecursiveNano.RecursiveMessageNano; +import com.google.protobuf.nano.NanoReferenceTypesCompat; import com.google.protobuf.nano.UnittestSimpleNano.SimpleMessageNano; import com.google.protobuf.nano.UnittestSingleNano.SingleMessageNano; import com.google.protobuf.nano.testext.Extensions; @@ -2300,6 +2302,59 @@ public class NanoTest extends TestCase { } } + public void testDifferentStringLengthsNano() throws Exception { + // Test string serialization roundtrip using strings of the following lengths, + // with ASCII and Unicode characters requiring different UTF-8 byte counts per + // char, hence causing the length delimiter varint to sometimes require more + // bytes for the Unicode strings than the ASCII string of the same length. + int[] lengths = new int[] { + 0, + 1, + (1 << 4) - 1, // 1 byte for ASCII and Unicode + (1 << 7) - 1, // 1 byte for ASCII, 2 bytes for Unicode + (1 << 11) - 1, // 2 bytes for ASCII and Unicode + (1 << 14) - 1, // 2 bytes for ASCII, 3 bytes for Unicode + (1 << 17) - 1, // 3 bytes for ASCII and Unicode + }; + for (int i : lengths) { + testEncodingOfString('q', i); // 1 byte per char + testEncodingOfString('\u07FF', i); // 2 bytes per char + testEncodingOfString('\u0981', i); // 3 bytes per char + } + } + + /** Regression test for https://github.com/google/protobuf/issues/292 */ + public void testCorrectExceptionThrowWhenEncodingStringsWithoutEnoughSpace() throws Exception { + String testCase = "Foooooooo"; + assertEquals(CodedOutputByteBufferNano.computeRawVarint32Size(testCase.length()), + CodedOutputByteBufferNano.computeRawVarint32Size(testCase.length() * 3)); + assertEquals(11, CodedOutputByteBufferNano.computeStringSize(1, testCase)); + // Tag is one byte, varint describing string length is 1 byte, string length is 9 bytes. + // An array of size 1 will cause a failure when trying to write the varint. + for (int i = 0; i < 11; i++) { + CodedOutputByteBufferNano bufferNano = CodedOutputByteBufferNano.newInstance(new byte[i]); + try { + bufferNano.writeString(1, testCase); + fail("Should have thrown an out of space exception"); + } catch (CodedOutputByteBufferNano.OutOfSpaceException expected) {} + } + } + + private void testEncodingOfString(char c, int length) throws InvalidProtocolBufferNanoException { + TestAllTypesNano testAllTypesNano = new TestAllTypesNano(); + final String fullString = fullString(c, length); + testAllTypesNano.optionalString = fullString; + final TestAllTypesNano resultNano = new TestAllTypesNano(); + MessageNano.mergeFrom(resultNano, MessageNano.toByteArray(testAllTypesNano)); + assertEquals(fullString, resultNano.optionalString); + } + + private String fullString(char c, int length) { + char[] result = new char[length]; + Arrays.fill(result, c); + return new String(result); + } + public void testNanoWithHasParseFrom() throws Exception { TestAllTypesNanoHas msg = null; // Test false on creation, after clear and upon empty parse. @@ -2986,6 +3041,10 @@ public class NanoTest extends TestCase { assertTrue(Arrays.equals(floats, message.getExtension(RepeatedExtensions.repeatedFloat))); assertTrue(Arrays.equals(doubles, message.getExtension(RepeatedExtensions.repeatedDouble))); assertTrue(Arrays.equals(enums, message.getExtension(RepeatedExtensions.repeatedEnum))); + + // Clone the message and ensure it's still equal. + Extensions.ExtendableMessage clone = message.clone(); + assertEquals(clone, message); } public void testNullExtensions() throws Exception { @@ -4345,6 +4404,11 @@ public class NanoTest extends TestCase { assertMapSet(testMap.sfixed64ToSfixed64Field, int64Values, int64Values); } + public void testRepeatedFieldInitializedInReftypesCompatMode() { + NanoReferenceTypesCompat.TestAllTypesNano proto = new NanoReferenceTypesCompat.TestAllTypesNano(); + assertNotNull(proto.repeatedString); + } + private void assertRepeatedPackablesEqual( NanoRepeatedPackables.NonPacked nonPacked, NanoRepeatedPackables.Packed packed) { // Not using MessageNano.equals() -- that belongs to a separate test. @@ -4364,6 +4428,22 @@ public class NanoTest extends TestCase { assertTrue(Arrays.equals(nonPacked.enums, packed.enums)); } + public void testClone() throws Exception { + // A simple message. + AnotherMessage anotherMessage = new AnotherMessage(); + anotherMessage.string = "Hello"; + anotherMessage.value = true; + anotherMessage.integers = new int[] { 1, 2, 3 }; + + AnotherMessage clone = anotherMessage.clone(); + assertEquals(clone, anotherMessage); + + // Verify it was a deep clone - changes to the clone shouldn't affect the + // original. + clone.integers[1] = 100; + assertFalse(clone.equals(anotherMessage)); + } + private void assertHasWireData(MessageNano message, boolean expected) { byte[] bytes = MessageNano.toByteArray(message); int wireLength = bytes.length; diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto index 2a678a80..ca56b3dd 100644 --- a/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto +++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto @@ -16,11 +16,15 @@ enum AnEnum { message AnotherMessage { optional string string = 1; optional bool value = 2; + repeated int32 integers = 3; } message ContainerMessage { extend ExtendableMessage { optional bool another_thing = 100; + // The largest permitted field number, per + // https://developers.google.com/protocol-buffers/docs/proto#simple + optional bool large_field_number = 536870911; } } diff --git a/objectivec/DevTools/check_version_stamps.sh b/objectivec/DevTools/check_version_stamps.sh new file mode 100755 index 00000000..5de9ef14 --- /dev/null +++ b/objectivec/DevTools/check_version_stamps.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +# This script checks that the runtime version number constant in the compiler +# source and in the runtime source is the same. +# +# A distro can be made of the protobuf sources with only a subset of the +# languages, so if the compiler depended on the Objective C runtime, those +# builds would break. At the same time, we don't want the runtime source +# depending on the compiler sources; so two copies of the constant are needed. + +set -eu + +readonly ScriptDir=$(dirname "$(echo $0 | sed -e "s,^\([^/]\),$(pwd)/\1,")") +readonly ProtoRootDir="${ScriptDir}/../.." + +die() { + echo "Error: $1" + exit 1 +} + +readonly ConstantName=GOOGLE_PROTOBUF_OBJC_GEN_VERSION + +# Collect version from plugin sources. + +readonly PluginSrc="${ProtoRootDir}/src/google/protobuf/compiler/objectivec/objectivec_file.cc" +readonly PluginVersion=$( \ + cat "${PluginSrc}" \ + | sed -n -e "s:const int32_t ${ConstantName} = \([0-9]*\);:\1:p" +) + +if [[ -z "${PluginVersion}" ]] ; then + die "Failed to fine ${ConstantName} in the plugin source (${PluginSrc})." +fi + +# Collect version from runtime sources. + +readonly RuntimeSrc="${ProtoRootDir}/objectivec/GPBBootstrap.h" +readonly RuntimeVersion=$( \ + cat "${RuntimeSrc}" \ + | sed -n -e "s:#define ${ConstantName} \([0-9]*\):\1:p" +) + +if [[ -z "${RuntimeVersion}" ]] ; then + die "Failed to fine ${ConstantName} in the runtime source (${RuntimeSrc})." +fi + +# Compare them. + +if [[ "${PluginVersion}" != "${RuntimeVersion}" ]] ; then + die "Versions don't match! + Plugin: ${PluginVersion} from ${PluginSrc} + Runtime: ${RuntimeVersion} from ${RuntimeSrc} +" +fi + +# Success diff --git a/objectivec/DevTools/generate_descriptors_proto.sh b/objectivec/DevTools/generate_descriptors_proto.sh new file mode 100755 index 00000000..42502bfe --- /dev/null +++ b/objectivec/DevTools/generate_descriptors_proto.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +# This script will generate the common descriptors needed by the Objective C +# runtime. + +# HINT: Flags passed to generate_descriptor_proto.sh will be passed directly +# to make when building protoc. This is particularly useful for passing +# -j4 to run 4 jobs simultaneously. + +set -eu + +readonly ScriptDir=$(dirname "$(echo $0 | sed -e "s,^\([^/]\),$(pwd)/\1,")") +readonly ProtoRootDir="${ScriptDir}/../.." +readonly ProtoC="${ProtoRootDir}/src/protoc" + +pushd "${ProtoRootDir}" > /dev/null + +# Compiler build fails if config.h hasn't been made yet (even if configure/etc. +# have been run, so get that made first). +make $@ config.h + +# Make sure the compiler is current. +cd src +make $@ protoc + +# These really should only be run when the inputs or compiler are newer than +# the outputs. + +# Needed by the runtime. +./protoc --objc_out="${ProtoRootDir}/objectivec" google/protobuf/descriptor.proto + +# Well known types that the library provides helpers for. +./protoc --objc_out="${ProtoRootDir}/objectivec" google/protobuf/timestamp.proto +./protoc --objc_out="${ProtoRootDir}/objectivec" google/protobuf/duration.proto + +popd > /dev/null diff --git a/objectivec/DevTools/pddm.py b/objectivec/DevTools/pddm.py new file mode 100755 index 00000000..d1b53f5a --- /dev/null +++ b/objectivec/DevTools/pddm.py @@ -0,0 +1,687 @@ +#! /usr/bin/python +# +# Protocol Buffers - Google's data interchange format +# Copyright 2015 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. + +"""PDDM - Poor Developers' Debug-able Macros + +A simple markup that can be added in comments of source so they can then be +expanded out into code. Most of this could be done with CPP macros, but then +developers can't really step through them in the debugger, this way they are +expanded to the same code, but you can debug them. + +Any file can be processed, but the syntax is designed around a C based compiler. +Processed lines start with "//%". There are three types of sections you can +create: Text (left alone), Macro Definitions, and Macro Expansions. There is +no order required between definitions and expansions, all definitions are read +before any expansions are processed (thus, if desired, definitions can be put +at the end of the file to keep them out of the way of the code). + +Macro Definitions are started with "//%PDDM-DEFINE Name(args)" and all lines +afterwards that start with "//%" are included in the definition. Multiple +macros can be defined in one block by just using a another "//%PDDM-DEFINE" +line to start the next macro. Optionally, a macro can be ended with +"//%PDDM-DEFINE-END", this can be useful when you want to make it clear that +trailing blank lines are included in the macro. You can also end a definition +with an expansion. + +Macro Expansions are started by single lines containing +"//%PDDM-EXPAND Name(args)" and then with "//%PDDM-EXPAND-END" or another +expansions. All lines in-between are replaced by the result of the expansion. +The first line of the expansion is always a blank like just for readability. + +Expansion itself is pretty simple, one macro can invoke another macro, but +you cannot nest the invoke of a macro in another macro (i.e. - can't do +"foo(bar(a))", but you can define foo(a) and bar(b) where bar invokes foo() +within its expansion. + +When macros are expanded, the arg references can also add "$O" suffix to the +name (i.e. - "NAME$O") to specify an option to be applied. The options are: + + $S - Replace each character in the value with a space. + $l - Lowercase the first letter of the value. + $L - Lowercase the whole value. + $u - Uppercase the first letter of the value. + $U - Uppercase the whole value. + +Within a macro you can use ## to cause things to get joined together after +expansion (i.e. - "a##b" within a macro will become "ab"). + +Example: + + int foo(MyEnum x) { + switch (x) { + //%PDDM-EXPAND case(Enum_Left, 1) + //%PDDM-EXPAND case(Enum_Center, 2) + //%PDDM-EXPAND case(Enum_Right, 3) + //%PDDM-EXPAND-END + } + + //%PDDM-DEFINE case(_A, _B) + //% case _A: + //% return _B; + + A macro ends at the start of the next one, or an optional %PDDM-DEFINE-END + can be used to avoid adding extra blank lines/returns (or make it clear when + it is desired). + + One macro can invoke another by simply using its name NAME(ARGS). You cannot + nest an invoke inside another (i.e. - NAME1(NAME2(ARGS)) isn't supported). + + Within a macro you can use ## to cause things to get joined together after + processing (i.e. - "a##b" within a macro will become "ab"). + + +""" + +import optparse +import os +import re +import sys + + +# Regex for macro definition. +_MACRO_RE = re.compile(r'(?P<name>\w+)\((?P<args>.*?)\)') +# Regex for macro's argument definition. +_MACRO_ARG_NAME_RE = re.compile(r'^\w+$') + +# Line inserted after each EXPAND. +_GENERATED_CODE_LINE = ( + '// This block of code is generated, do not edit it directly.' +) + + +def _MacroRefRe(macro_names): + # Takes in a list of macro names and makes a regex that will match invokes + # of those macros. + return re.compile(r'\b(?P<macro_ref>(?P<name>(%s))\((?P<args>.*?)\))' % + '|'.join(macro_names)) + +def _MacroArgRefRe(macro_arg_names): + # Takes in a list of macro arg names and makes a regex that will match + # uses of those args. + return re.compile(r'\b(?P<name>(%s))(\$(?P<option>.))?\b' % + '|'.join(macro_arg_names)) + + +class PDDMError(Exception): + """Error thrown by pddm.""" + pass + + +class MacroCollection(object): + """Hold a set of macros and can resolve/expand them.""" + + def __init__(self, a_file=None): + """Initializes the collection. + + Args: + a_file: The file like stream to parse. + + Raises: + PDDMError if there are any issues. + """ + self._macros = dict() + if a_file: + self.ParseInput(a_file) + + class MacroDefinition(object): + """Holds a macro definition.""" + + def __init__(self, name, arg_names): + self._name = name + self._args = tuple(arg_names) + self._body = '' + self._needNewLine = False + + def AppendLine(self, line): + if self._needNewLine: + self._body += '\n' + self._body += line + self._needNewLine = not line.endswith('\n') + + @property + def name(self): + return self._name + + @property + def args(self): + return self._args + + @property + def body(self): + return self._body + + def ParseInput(self, a_file): + """Consumes input extracting definitions. + + Args: + a_file: The file like stream to parse. + + Raises: + PDDMError if there are any issues. + """ + input_lines = a_file.read().splitlines() + self.ParseLines(input_lines) + + def ParseLines(self, input_lines): + """Parses list of lines. + + Args: + input_lines: A list of strings of input to parse (no newlines on the + strings). + + Raises: + PDDMError if there are any issues. + """ + current_macro = None + for line in input_lines: + if line.startswith('PDDM-'): + directive = line.split(' ', 1)[0] + if directive == 'PDDM-DEFINE': + name, args = self._ParseDefineLine(line) + if self._macros.get(name): + raise PDDMError('Attempt to redefine macro: "%s"' % line) + current_macro = self.MacroDefinition(name, args) + self._macros[name] = current_macro + continue + if directive == 'PDDM-DEFINE-END': + if not current_macro: + raise PDDMError('Got DEFINE-END directive without an active macro:' + ' "%s"' % line) + current_macro = None + continue + raise PDDMError('Hit a line with an unknown directive: "%s"' % line) + + if current_macro: + current_macro.AppendLine(line) + continue + + # Allow blank lines between macro definitions. + if line.strip() == '': + continue + + raise PDDMError('Hit a line that wasn\'t a directive and no open macro' + ' definition: "%s"' % line) + + def _ParseDefineLine(self, input_line): + assert input_line.startswith('PDDM-DEFINE') + line = input_line[12:].strip() + match = _MACRO_RE.match(line) + # Must match full line + if match is None or match.group(0) != line: + raise PDDMError('Failed to parse macro definition: "%s"' % input_line) + name = match.group('name') + args_str = match.group('args').strip() + args = [] + if args_str: + for part in args_str.split(','): + arg = part.strip() + if arg == '': + raise PDDMError('Empty arg name in macro definition: "%s"' + % input_line) + if not _MACRO_ARG_NAME_RE.match(arg): + raise PDDMError('Invalid arg name "%s" in macro definition: "%s"' + % (arg, input_line)) + if arg in args: + raise PDDMError('Arg name "%s" used more than once in macro' + ' definition: "%s"' % (arg, input_line)) + args.append(arg) + return (name, tuple(args)) + + def Expand(self, macro_ref_str): + """Expands the macro reference. + + Args: + macro_ref_str: String of a macro reference (i.e. foo(a, b)). + + Returns: + The text from the expansion. + + Raises: + PDDMError if there are any issues. + """ + match = _MACRO_RE.match(macro_ref_str) + if match is None or match.group(0) != macro_ref_str: + raise PDDMError('Failed to parse macro reference: "%s"' % macro_ref_str) + if match.group('name') not in self._macros: + raise PDDMError('No macro named "%s".' % match.group('name')) + return self._Expand(match, [], macro_ref_str) + + def _FormatStack(self, macro_ref_stack): + result = '' + for _, macro_ref in reversed(macro_ref_stack): + result += '\n...while expanding "%s".' % macro_ref + return result + + def _Expand(self, macro_ref_match, macro_stack, macro_ref_str=None): + if macro_ref_str is None: + macro_ref_str = macro_ref_match.group('macro_ref') + name = macro_ref_match.group('name') + for prev_name, prev_macro_ref in macro_stack: + if name == prev_name: + raise PDDMError('Found macro recusion, invoking "%s":%s' % + (macro_ref_str, self._FormatStack(macro_stack))) + macro = self._macros[name] + args_str = macro_ref_match.group('args').strip() + args = [] + if args_str or len(macro.args): + args = [x.strip() for x in args_str.split(',')] + if len(args) != len(macro.args): + raise PDDMError('Expected %d args, got: "%s".%s' % + (len(macro.args), macro_ref_str, + self._FormatStack(macro_stack))) + # Replace args usages. + result = self._ReplaceArgValues(macro, args, macro_ref_str, macro_stack) + # Expand any macro invokes. + new_macro_stack = macro_stack + [(name, macro_ref_str)] + while True: + eval_result = self._EvalMacrosRefs(result, new_macro_stack) + # Consume all ## directives to glue things together. + eval_result = eval_result.replace('##', '') + if eval_result == result: + break + result = eval_result + return result + + def _ReplaceArgValues(self, + macro, arg_values, macro_ref_to_report, macro_stack): + if len(arg_values) == 0: + # Nothing to do + return macro.body + assert len(arg_values) == len(macro.args) + args = dict(zip(macro.args, arg_values)) + def _lookupArg(match): + val = args[match.group('name')] + opt = match.group('option') + if opt: + if opt == 'S': # Spaces for the length + return ' ' * len(val) + elif opt == 'l': # Lowercase first character + if val: + return val[0].lower() + val[1:] + else: + return val + elif opt == 'L': # All Lowercase + return val.lower() + elif opt == 'u': # Uppercase first character + if val: + return val[0].upper() + val[1:] + else: + return val + elif opt == 'U': # All Uppercase + return val.upper() + else: + raise PDDMError('Unknown arg option "%s$%s" while expanding "%s".%s' + % (match.group('name'), match.group('option'), + macro_ref_to_report, + self._FormatStack(macro_stack))) + return val + # Let the regex do the work! + macro_arg_ref_re = _MacroArgRefRe(macro.args) + return macro_arg_ref_re.sub(_lookupArg, macro.body) + + def _EvalMacrosRefs(self, text, macro_stack): + macro_ref_re = _MacroRefRe(self._macros.keys()) + def _resolveMacro(match): + return self._Expand(match, macro_stack) + return macro_ref_re.sub(_resolveMacro, text) + + +class SourceFile(object): + """Represents a source file with PDDM directives in it.""" + + def __init__(self, a_file, import_resolver=None): + """Initializes the file reading in the file. + + Args: + a_file: The file to read in. + import_resolver: a function that given a path will return a stream for + the contents. + + Raises: + PDDMError if there are any issues. + """ + self._sections = [] + self._original_content = a_file.read() + self._import_resolver = import_resolver + self._processed_content = None + + class SectionBase(object): + + def __init__(self, first_line_num): + self._lines = [] + self._first_line_num = first_line_num + + def TryAppend(self, line, line_num): + """Try appending a line. + + Args: + line: The line to append. + line_num: The number of the line. + + Returns: + A tuple of (SUCCESS, CAN_ADD_MORE). If SUCCESS if False, the line + wasn't append. If SUCCESS is True, then CAN_ADD_MORE is True/False to + indicate if more lines can be added after this one. + """ + assert False, "sublcass should have overridden" + return (False, False) + + def HitEOF(self): + """Called when the EOF was reached for for a given section.""" + pass + + def BindMacroCollection(self, macro_collection): + """Binds the chunk to a macro collection. + + Args: + macro_collection: The collection to bind too. + """ + pass + + def Append(self, line): + self._lines.append(line) + + @property + def lines(self): + return self._lines + + @property + def num_lines_captured(self): + return len(self._lines) + + @property + def first_line_num(self): + return self._first_line_num + + @property + def first_line(self): + if not self._lines: + return '' + return self._lines[0] + + @property + def text(self): + return '\n'.join(self.lines) + '\n' + + class TextSection(SectionBase): + """Text section that is echoed out as is.""" + + def TryAppend(self, line, line_num): + if line.startswith('//%PDDM'): + return (False, False) + self.Append(line) + return (True, True) + + class ExpansionSection(SectionBase): + """Section that is the result of an macro expansion.""" + + def __init__(self, first_line_num): + SourceFile.SectionBase.__init__(self, first_line_num) + self._macro_collection = None + + def TryAppend(self, line, line_num): + if line.startswith('//%PDDM'): + directive = line.split(' ', 1)[0] + if directive == '//%PDDM-EXPAND': + self.Append(line) + return (True, True) + if directive == '//%PDDM-EXPAND-END': + assert self.num_lines_captured > 0 + return (True, False) + raise PDDMError('Ran into directive ("%s", line %d) while in "%s".' % + (directive, line_num, self.first_line)) + # Eat other lines. + return (True, True) + + def HitEOF(self): + raise PDDMError('Hit the end of the file while in "%s".' % + self.first_line) + + def BindMacroCollection(self, macro_collection): + self._macro_collection = macro_collection + + @property + def lines(self): + captured_lines = SourceFile.SectionBase.lines.fget(self) + directive_len = len('//%PDDM-EXPAND') + result = [] + for line in captured_lines: + result.append(line) + if self._macro_collection: + # Always add a blank line, seems to read better. (If need be, add an + # option to the EXPAND to indicate if this should be done.) + result.extend([_GENERATED_CODE_LINE, '']) + macro = line[directive_len:].strip() + try: + expand_result = self._macro_collection.Expand(macro) + # Since expansions are line oriented, strip trailing whitespace + # from the lines. + lines = [x.rstrip() for x in expand_result.split('\n')] + result.append('\n'.join(lines)) + except PDDMError as e: + raise PDDMError('%s\n...while expanding "%s" from the section' + ' that started:\n Line %d: %s' % + (e.message, macro, + self.first_line_num, self.first_line)) + + # Add the ending marker. + if len(captured_lines) == 1: + result.append('//%%PDDM-EXPAND-END %s' % + captured_lines[0][directive_len:].strip()) + else: + result.append('//%%PDDM-EXPAND-END (%s expansions)' % len(captured_lines)) + + return result + + class DefinitionSection(SectionBase): + """Section containing macro definitions""" + + def TryAppend(self, line, line_num): + if not line.startswith('//%'): + return (False, False) + if line.startswith('//%PDDM'): + directive = line.split(' ', 1)[0] + if directive == "//%PDDM-EXPAND": + return False, False + if directive not in ('//%PDDM-DEFINE', '//%PDDM-DEFINE-END'): + raise PDDMError('Ran into directive ("%s", line %d) while in "%s".' % + (directive, line_num, self.first_line)) + self.Append(line) + return (True, True) + + def BindMacroCollection(self, macro_collection): + if macro_collection: + try: + # Parse the lines after stripping the prefix. + macro_collection.ParseLines([x[3:] for x in self.lines]) + except PDDMError as e: + raise PDDMError('%s\n...while parsing section that started:\n' + ' Line %d: %s' % + (e.message, self.first_line_num, self.first_line)) + + class ImportDefinesSection(SectionBase): + """Section containing an import of PDDM-DEFINES from an external file.""" + + def __init__(self, first_line_num, import_resolver): + SourceFile.SectionBase.__init__(self, first_line_num) + self._import_resolver = import_resolver + + def TryAppend(self, line, line_num): + if not line.startswith('//%PDDM-IMPORT-DEFINES '): + return (False, False) + assert self.num_lines_captured == 0 + self.Append(line) + return (True, False) + + def BindMacroCollection(self, macro_colletion): + if not macro_colletion: + return + if self._import_resolver is None: + raise PDDMError('Got an IMPORT-DEFINES without a resolver (line %d):' + ' "%s".' % (self.first_line_num, self.first_line)) + import_name = self.first_line.split(' ', 1)[1].strip() + imported_file = self._import_resolver(import_name) + if imported_file is None: + raise PDDMError('Resolver failed to find "%s" (line %d):' + ' "%s".' % + (import_name, self.first_line_num, self.first_line)) + try: + imported_src_file = SourceFile(imported_file, self._import_resolver) + imported_src_file._ParseFile() + for section in imported_src_file._sections: + section.BindMacroCollection(macro_colletion) + except PDDMError as e: + raise PDDMError('%s\n...while importing defines:\n' + ' Line %d: %s' % + (e.message, self.first_line_num, self.first_line)) + + def _ParseFile(self): + self._sections = [] + lines = self._original_content.splitlines() + cur_section = None + for line_num, line in enumerate(lines, 1): + if not cur_section: + cur_section = self._MakeSection(line, line_num) + was_added, accept_more = cur_section.TryAppend(line, line_num) + if not was_added: + cur_section = self._MakeSection(line, line_num) + was_added, accept_more = cur_section.TryAppend(line, line_num) + assert was_added + if not accept_more: + cur_section = None + + if cur_section: + cur_section.HitEOF() + + def _MakeSection(self, line, line_num): + if not line.startswith('//%PDDM'): + section = self.TextSection(line_num) + else: + directive = line.split(' ', 1)[0] + if directive == '//%PDDM-EXPAND': + section = self.ExpansionSection(line_num) + elif directive == '//%PDDM-DEFINE': + section = self.DefinitionSection(line_num) + elif directive == '//%PDDM-IMPORT-DEFINES': + section = self.ImportDefinesSection(line_num, self._import_resolver) + else: + raise PDDMError('Unexpected line %d: "%s".' % (line_num, line)) + self._sections.append(section) + return section + + def ProcessContent(self, strip_expansion=False): + """Processes the file contents.""" + self._ParseFile() + if strip_expansion: + # Without a collection the expansions become blank, removing them. + collection = None + else: + collection = MacroCollection() + for section in self._sections: + section.BindMacroCollection(collection) + result = '' + for section in self._sections: + result += section.text + self._processed_content = result + + @property + def original_content(self): + return self._original_content + + @property + def processed_content(self): + return self._processed_content + + +def main(args): + usage = '%prog [OPTIONS] PATH ...' + description = ( + 'Processes PDDM directives in the the given paths and write them back' + ' out.' + ) + parser = optparse.OptionParser(usage=usage, description=description) + parser.add_option('--dry-run', + default=False, action='store_true', + help='Don\'t write back to the file(s), just report if the' + ' contents needs an update and exit with a value of 1.') + parser.add_option('--verbose', + default=False, action='store_true', + help='Reports is a file is already current.') + parser.add_option('--collapse', + default=False, action='store_true', + help='Removes all the generated code.') + opts, extra_args = parser.parse_args(args) + + if not extra_args: + parser.error('Need atleast one file to process') + + result = 0 + for a_path in extra_args: + if not os.path.exists(a_path): + sys.stderr.write('ERROR: File not found: %s\n' % a_path) + return 100 + + def _ImportResolver(name): + # resolve based on the file being read. + a_dir = os.path.dirname(a_path) + import_path = os.path.join(a_dir, name) + if not os.path.exists(import_path): + return None + return open(import_path, 'r') + + with open(a_path, 'r') as f: + src_file = SourceFile(f, _ImportResolver) + + try: + src_file.ProcessContent(strip_expansion=opts.collapse) + except PDDMError as e: + sys.stderr.write('ERROR: %s\n...While processing "%s"\n' % + (e.message, a_path)) + return 101 + + if src_file.processed_content != src_file.original_content: + if not opts.dry_run: + print 'Updating for "%s".' % a_path + with open(a_path, 'w') as f: + f.write(src_file.processed_content) + else: + # Special result to indicate things need updating. + print 'Update needed for "%s".' % a_path + result = 1 + elif opts.verbose: + print 'No update for "%s".' % a_path + + return result + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/objectivec/DevTools/pddm_tests.py b/objectivec/DevTools/pddm_tests.py new file mode 100755 index 00000000..8a73b842 --- /dev/null +++ b/objectivec/DevTools/pddm_tests.py @@ -0,0 +1,515 @@ +#! /usr/bin/python +# +# Protocol Buffers - Google's data interchange format +# Copyright 2015 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. + +"""Tests for pddm.py.""" + +import io +import unittest + +import pddm + + +class TestParsingMacros(unittest.TestCase): + + def testParseEmpty(self): + f = io.StringIO(u'') + result = pddm.MacroCollection(f) + self.assertEqual(len(result._macros), 0) + + def testParseOne(self): + f = io.StringIO(u"""PDDM-DEFINE foo( ) +body""") + result = pddm.MacroCollection(f) + self.assertEqual(len(result._macros), 1) + macro = result._macros.get('foo') + self.assertIsNotNone(macro) + self.assertEquals(macro.name, 'foo') + self.assertEquals(macro.args, tuple()) + self.assertEquals(macro.body, 'body') + + def testParseGeneral(self): + # Tests multiple defines, spaces in all places, etc. + f = io.StringIO(u""" +PDDM-DEFINE noArgs( ) +body1 +body2 + +PDDM-DEFINE-END + +PDDM-DEFINE oneArg(foo) +body3 +PDDM-DEFINE twoArgs( bar_ , baz ) +body4 +body5""") + result = pddm.MacroCollection(f) + self.assertEqual(len(result._macros), 3) + macro = result._macros.get('noArgs') + self.assertIsNotNone(macro) + self.assertEquals(macro.name, 'noArgs') + self.assertEquals(macro.args, tuple()) + self.assertEquals(macro.body, 'body1\nbody2\n') + macro = result._macros.get('oneArg') + self.assertIsNotNone(macro) + self.assertEquals(macro.name, 'oneArg') + self.assertEquals(macro.args, ('foo',)) + self.assertEquals(macro.body, 'body3') + macro = result._macros.get('twoArgs') + self.assertIsNotNone(macro) + self.assertEquals(macro.name, 'twoArgs') + self.assertEquals(macro.args, ('bar_', 'baz')) + self.assertEquals(macro.body, 'body4\nbody5') + # Add into existing collection + f = io.StringIO(u""" +PDDM-DEFINE another(a,b,c) +body1 +body2""") + result.ParseInput(f) + self.assertEqual(len(result._macros), 4) + macro = result._macros.get('another') + self.assertIsNotNone(macro) + self.assertEquals(macro.name, 'another') + self.assertEquals(macro.args, ('a', 'b', 'c')) + self.assertEquals(macro.body, 'body1\nbody2') + + def testParseDirectiveIssues(self): + test_list = [ + # Unknown directive + (u'PDDM-DEFINE foo()\nbody\nPDDM-DEFINED foo\nbaz', + 'Hit a line with an unknown directive: '), + # End without begin + (u'PDDM-DEFINE foo()\nbody\nPDDM-DEFINE-END\nPDDM-DEFINE-END\n', + 'Got DEFINE-END directive without an active macro: '), + # Line not in macro block + (u'PDDM-DEFINE foo()\nbody\nPDDM-DEFINE-END\nmumble\n', + 'Hit a line that wasn\'t a directive and no open macro definition: '), + # Redefine macro + (u'PDDM-DEFINE foo()\nbody\nPDDM-DEFINE foo(a)\nmumble\n', + 'Attempt to redefine macro: '), + ] + for idx, (input_str, expected_prefix) in enumerate(test_list, 1): + f = io.StringIO(input_str) + try: + result = pddm.MacroCollection(f) + self.fail('Should throw exception, entry %d' % idx) + except pddm.PDDMError as e: + self.assertTrue(e.message.startswith(expected_prefix), + 'Entry %d failed: %r' % (idx, e)) + + def testParseBeginIssues(self): + test_list = [ + # 1. No name + (u'PDDM-DEFINE\nmumble', + 'Failed to parse macro definition: '), + # 2. No name (with spaces) + (u'PDDM-DEFINE \nmumble', + 'Failed to parse macro definition: '), + # 3. No open paren + (u'PDDM-DEFINE foo\nmumble', + 'Failed to parse macro definition: '), + # 4. No close paren + (u'PDDM-DEFINE foo(\nmumble', + 'Failed to parse macro definition: '), + # 5. No close paren (with args) + (u'PDDM-DEFINE foo(a, b\nmumble', + 'Failed to parse macro definition: '), + # 6. No name before args + (u'PDDM-DEFINE (a, b)\nmumble', + 'Failed to parse macro definition: '), + # 7. No name before args + (u'PDDM-DEFINE foo bar(a, b)\nmumble', + 'Failed to parse macro definition: '), + # 8. Empty arg name + (u'PDDM-DEFINE foo(a, ,b)\nmumble', + 'Empty arg name in macro definition: '), + (u'PDDM-DEFINE foo(a,,b)\nmumble', + 'Empty arg name in macro definition: '), + # 10. Duplicate name + (u'PDDM-DEFINE foo(a,b,a,c)\nmumble', + 'Arg name "a" used more than once in macro definition: '), + # 11. Invalid arg name + (u'PDDM-DEFINE foo(a b,c)\nmumble', + 'Invalid arg name "a b" in macro definition: '), + (u'PDDM-DEFINE foo(a.b,c)\nmumble', + 'Invalid arg name "a.b" in macro definition: '), + (u'PDDM-DEFINE foo(a-b,c)\nmumble', + 'Invalid arg name "a-b" in macro definition: '), + (u'PDDM-DEFINE foo(a,b,c.)\nmumble', + 'Invalid arg name "c." in macro definition: '), + # 15. Extra stuff after the name + (u'PDDM-DEFINE foo(a,c) foo\nmumble', + 'Failed to parse macro definition: '), + (u'PDDM-DEFINE foo(a,c) foo)\nmumble', + 'Failed to parse macro definition: '), + ] + for idx, (input_str, expected_prefix) in enumerate(test_list, 1): + f = io.StringIO(input_str) + try: + result = pddm.MacroCollection(f) + self.fail('Should throw exception, entry %d' % idx) + except pddm.PDDMError as e: + self.assertTrue(e.message.startswith(expected_prefix), + 'Entry %d failed: %r' % (idx, e)) + + +class TestExpandingMacros(unittest.TestCase): + + def testExpandBasics(self): + f = io.StringIO(u""" +PDDM-DEFINE noArgs( ) +body1 +body2 + +PDDM-DEFINE-END + +PDDM-DEFINE oneArg(a) +body3 a + +PDDM-DEFINE-END + +PDDM-DEFINE twoArgs(b,c) +body4 b c +body5 +PDDM-DEFINE-END + +""") + mc = pddm.MacroCollection(f) + test_list = [ + (u'noArgs()', + 'body1\nbody2\n'), + (u'oneArg(wee)', + 'body3 wee\n'), + (u'twoArgs(having some, fun)', + 'body4 having some fun\nbody5'), + # One arg, pass empty. + (u'oneArg()', + 'body3 \n'), + # Two args, gets empty in each slot. + (u'twoArgs(, empty)', + 'body4 empty\nbody5'), + (u'twoArgs(empty, )', + 'body4 empty \nbody5'), + (u'twoArgs(, )', + 'body4 \nbody5'), + ] + for idx, (input_str, expected) in enumerate(test_list, 1): + result = mc.Expand(input_str) + self.assertEqual(result, expected, + 'Entry %d --\n Result: %r\n Expected: %r' % + (idx, result, expected)) + + def testExpandArgOptions(self): + f = io.StringIO(u""" +PDDM-DEFINE bar(a) +a-a$S-a$l-a$L-a$u-a$U +PDDM-DEFINE-END +""") + mc = pddm.MacroCollection(f) + + self.assertEqual(mc.Expand('bar(xYz)'), 'xYz- -xYz-xyz-XYz-XYZ') + self.assertEqual(mc.Expand('bar(MnoP)'), 'MnoP- -mnoP-mnop-MnoP-MNOP') + # Test empty + self.assertEqual(mc.Expand('bar()'), '-----') + + def testExpandSimpleMacroErrors(self): + f = io.StringIO(u""" +PDDM-DEFINE foo(a, b) +<a-z> +PDDM-DEFINE baz(a) +a - a$z +""") + mc = pddm.MacroCollection(f) + test_list = [ + # 1. Unknown macro + (u'bar()', + 'No macro named "bar".'), + (u'bar(a)', + 'No macro named "bar".'), + # 3. Arg mismatch + (u'foo()', + 'Expected 2 args, got: "foo()".'), + (u'foo(a b)', + 'Expected 2 args, got: "foo(a b)".'), + (u'foo(a,b,c)', + 'Expected 2 args, got: "foo(a,b,c)".'), + # 6. Unknown option in expansion + (u'baz(mumble)', + 'Unknown arg option "a$z" while expanding "baz(mumble)".'), + ] + for idx, (input_str, expected_err) in enumerate(test_list, 1): + try: + result = mc.Expand(input_str) + self.fail('Should throw exception, entry %d' % idx) + except pddm.PDDMError as e: + self.assertEqual(e.message, expected_err, + 'Entry %d failed: %r' % (idx, e)) + + def testExpandReferences(self): + f = io.StringIO(u""" +PDDM-DEFINE StartIt() +foo(abc, def) +foo(ghi, jkl) +PDDM-DEFINE foo(a, b) +bar(a, int) +bar(b, NSString *) +PDDM-DEFINE bar(n, t) +- (t)n; +- (void)set##n$u##:(t)value; + +""") + mc = pddm.MacroCollection(f) + expected = """- (int)abc; +- (void)setAbc:(int)value; + +- (NSString *)def; +- (void)setDef:(NSString *)value; + +- (int)ghi; +- (void)setGhi:(int)value; + +- (NSString *)jkl; +- (void)setJkl:(NSString *)value; +""" + self.assertEqual(mc.Expand('StartIt()'), expected) + + def testCatchRecursion(self): + f = io.StringIO(u""" +PDDM-DEFINE foo(a, b) +bar(1, a) +bar(2, b) +PDDM-DEFINE bar(x, y) +foo(x, y) +""") + mc = pddm.MacroCollection(f) + try: + result = mc.Expand('foo(A,B)') + self.fail('Should throw exception, entry %d' % idx) + except pddm.PDDMError as e: + self.assertEqual(e.message, + 'Found macro recusion, invoking "foo(1, A)":\n...while expanding "bar(1, A)".\n...while expanding "foo(A,B)".') + + +class TestParsingSource(unittest.TestCase): + + def testBasicParse(self): + test_list = [ + # 1. no directives + (u'a\nb\nc', + (3,) ), + # 2. One define + (u'a\n//%PDDM-DEFINE foo()\n//%body\nc', + (1, 2, 1) ), + # 3. Two defines + (u'a\n//%PDDM-DEFINE foo()\n//%body\n//%PDDM-DEFINE bar()\n//%body2\nc', + (1, 4, 1) ), + # 4. Two defines with ends + (u'a\n//%PDDM-DEFINE foo()\n//%body\n//%PDDM-DEFINE-END\n' + u'//%PDDM-DEFINE bar()\n//%body2\n//%PDDM-DEFINE-END\nc', + (1, 6, 1) ), + # 5. One expand, one define (that runs to end of file) + (u'a\n//%PDDM-EXPAND foo()\nbody\n//%PDDM-EXPAND-END\n' + u'//%PDDM-DEFINE bar()\n//%body2\n', + (1, 1, 2) ), + # 6. One define ended with an expand. + (u'a\nb\n//%PDDM-DEFINE bar()\n//%body2\n' + u'//%PDDM-EXPAND bar()\nbody2\n//%PDDM-EXPAND-END\n', + (2, 2, 1) ), + # 7. Two expands (one end), one define. + (u'a\n//%PDDM-EXPAND foo(1)\nbody\n//%PDDM-EXPAND foo(2)\nbody2\n//%PDDM-EXPAND-END\n' + u'//%PDDM-DEFINE foo()\n//%body2\n', + (1, 2, 2) ), + ] + for idx, (input_str, line_counts) in enumerate(test_list, 1): + f = io.StringIO(input_str) + sf = pddm.SourceFile(f) + sf._ParseFile() + self.assertEqual(len(sf._sections), len(line_counts), + 'Entry %d -- %d != %d' % + (idx, len(sf._sections), len(line_counts))) + for idx2, (sec, expected) in enumerate(zip(sf._sections, line_counts), 1): + self.assertEqual(sec.num_lines_captured, expected, + 'Entry %d, section %d -- %d != %d' % + (idx, idx2, sec.num_lines_captured, expected)) + + def testErrors(self): + test_list = [ + # 1. Directive within expansion + (u'//%PDDM-EXPAND a()\n//%PDDM-BOGUS', + 'Ran into directive ("//%PDDM-BOGUS", line 2) while in "//%PDDM-EXPAND a()".'), + (u'//%PDDM-EXPAND a()\n//%PDDM-DEFINE a()\n//%body\n', + 'Ran into directive ("//%PDDM-DEFINE", line 2) while in "//%PDDM-EXPAND a()".'), + # 3. Expansion ran off end of file + (u'//%PDDM-EXPAND a()\na\nb\n', + 'Hit the end of the file while in "//%PDDM-EXPAND a()".'), + # 4. Directive within define + (u'//%PDDM-DEFINE a()\n//%body\n//%PDDM-BOGUS', + 'Ran into directive ("//%PDDM-BOGUS", line 3) while in "//%PDDM-DEFINE a()".'), + (u'//%PDDM-DEFINE a()\n//%body\n//%PDDM-EXPAND-END a()', + 'Ran into directive ("//%PDDM-EXPAND-END", line 3) while in "//%PDDM-DEFINE a()".'), + # 6. Directives that shouldn't start sections + (u'a\n//%PDDM-DEFINE-END a()\n//a\n', + 'Unexpected line 2: "//%PDDM-DEFINE-END a()".'), + (u'a\n//%PDDM-EXPAND-END a()\n//a\n', + 'Unexpected line 2: "//%PDDM-EXPAND-END a()".'), + (u'//%PDDM-BOGUS\n//a\n', + 'Unexpected line 1: "//%PDDM-BOGUS".'), + ] + for idx, (input_str, expected_err) in enumerate(test_list, 1): + f = io.StringIO(input_str) + try: + pddm.SourceFile(f)._ParseFile() + self.fail('Should throw exception, entry %d' % idx) + except pddm.PDDMError as e: + self.assertEqual(e.message, expected_err, + 'Entry %d failed: %r' % (idx, e)) + +class TestProcessingSource(unittest.TestCase): + + def testBasics(self): + input_str = u""" +//%PDDM-IMPORT-DEFINES ImportFile +foo +//%PDDM-EXPAND mumble(abc) +//%PDDM-EXPAND-END +bar +//%PDDM-EXPAND mumble(def) +//%PDDM-EXPAND mumble(ghi) +//%PDDM-EXPAND-END +baz +//%PDDM-DEFINE mumble(a_) +//%a_: getName(a_) +""" + input_str2 = u""" +//%PDDM-DEFINE getName(x_) +//%do##x_$u##(int x_); + +""" + expected = u""" +//%PDDM-IMPORT-DEFINES ImportFile +foo +//%PDDM-EXPAND mumble(abc) +// This block of code is generated, do not edit it directly. + +abc: doAbc(int abc); +//%PDDM-EXPAND-END mumble(abc) +bar +//%PDDM-EXPAND mumble(def) +// This block of code is generated, do not edit it directly. + +def: doDef(int def); +//%PDDM-EXPAND mumble(ghi) +// This block of code is generated, do not edit it directly. + +ghi: doGhi(int ghi); +//%PDDM-EXPAND-END (2 expansions) +baz +//%PDDM-DEFINE mumble(a_) +//%a_: getName(a_) +""" + expected_stripped = u""" +//%PDDM-IMPORT-DEFINES ImportFile +foo +//%PDDM-EXPAND mumble(abc) +//%PDDM-EXPAND-END mumble(abc) +bar +//%PDDM-EXPAND mumble(def) +//%PDDM-EXPAND mumble(ghi) +//%PDDM-EXPAND-END (2 expansions) +baz +//%PDDM-DEFINE mumble(a_) +//%a_: getName(a_) +""" + def _Resolver(name): + self.assertEqual(name, 'ImportFile') + return io.StringIO(input_str2) + f = io.StringIO(input_str) + sf = pddm.SourceFile(f, _Resolver) + sf.ProcessContent() + self.assertEqual(sf.processed_content, expected) + # Feed it through and nothing should change. + f2 = io.StringIO(sf.processed_content) + sf2 = pddm.SourceFile(f2, _Resolver) + sf2.ProcessContent() + self.assertEqual(sf2.processed_content, expected) + self.assertEqual(sf2.processed_content, sf.processed_content) + # Test stripping (with the original input and expanded version). + f2 = io.StringIO(input_str) + sf2 = pddm.SourceFile(f2) + sf2.ProcessContent(strip_expansion=True) + self.assertEqual(sf2.processed_content, expected_stripped) + f2 = io.StringIO(sf.processed_content) + sf2 = pddm.SourceFile(f2, _Resolver) + sf2.ProcessContent(strip_expansion=True) + self.assertEqual(sf2.processed_content, expected_stripped) + + def testProcessFileWithMacroParseError(self): + input_str = u""" +foo +//%PDDM-DEFINE mumble(a_) +//%body +//%PDDM-DEFINE mumble(x_) +//%body2 + +""" + f = io.StringIO(input_str) + sf = pddm.SourceFile(f) + try: + sf.ProcessContent() + self.fail('Should throw exception, entry %d' % idx) + except pddm.PDDMError as e: + self.assertEqual(e.message, + 'Attempt to redefine macro: "PDDM-DEFINE mumble(x_)"\n' + '...while parsing section that started:\n' + ' Line 3: //%PDDM-DEFINE mumble(a_)') + + def testProcessFileWithExpandError(self): + input_str = u""" +foo +//%PDDM-DEFINE mumble(a_) +//%body +//%PDDM-EXPAND foobar(x_) +//%PDDM-EXPAND-END + +""" + f = io.StringIO(input_str) + sf = pddm.SourceFile(f) + try: + sf.ProcessContent() + self.fail('Should throw exception, entry %d' % idx) + except pddm.PDDMError as e: + self.assertEqual(e.message, + 'No macro named "foobar".\n' + '...while expanding "foobar(x_)" from the section that' + ' started:\n Line 5: //%PDDM-EXPAND foobar(x_)') + + +if __name__ == '__main__': + unittest.main() diff --git a/objectivec/GPBArray.h b/objectivec/GPBArray.h new file mode 100644 index 00000000..3fcba7af --- /dev/null +++ b/objectivec/GPBArray.h @@ -0,0 +1,535 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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. + +#import <Foundation/Foundation.h> + +#import "GPBTypes.h" + +// These classes are used for repeated fields of basic data types. They are used because +// they perform better than boxing into NSNumbers in NSArrays. + +// Note: These are not meant to be subclassed. + +//%PDDM-EXPAND DECLARE_ARRAYS() +// This block of code is generated, do not edit it directly. + +#pragma mark - Int32 + +@interface GPBInt32Array : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)array; ++ (instancetype)arrayWithValue:(int32_t)value; ++ (instancetype)arrayWithValueArray:(GPBInt32Array *)array; ++ (instancetype)arrayWithCapacity:(NSUInteger)count; + +// Initializes the array, copying the values. +- (instancetype)initWithValues:(const int32_t [])values + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithValueArray:(GPBInt32Array *)array; +- (instancetype)initWithCapacity:(NSUInteger)count; + +- (int32_t)valueAtIndex:(NSUInteger)index; + +- (void)enumerateValuesWithBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block; +- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts + usingBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block; + +- (void)addValue:(int32_t)value; +- (void)addValues:(const int32_t [])values count:(NSUInteger)count; +- (void)addValuesFromArray:(GPBInt32Array *)array; + +- (void)insertValue:(int32_t)value atIndex:(NSUInteger)index; + +- (void)replaceValueAtIndex:(NSUInteger)index withValue:(int32_t)value; + +- (void)removeValueAtIndex:(NSUInteger)index; +- (void)removeAll; + +- (void)exchangeValueAtIndex:(NSUInteger)idx1 + withValueAtIndex:(NSUInteger)idx2; + +@end + +#pragma mark - UInt32 + +@interface GPBUInt32Array : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)array; ++ (instancetype)arrayWithValue:(uint32_t)value; ++ (instancetype)arrayWithValueArray:(GPBUInt32Array *)array; ++ (instancetype)arrayWithCapacity:(NSUInteger)count; + +// Initializes the array, copying the values. +- (instancetype)initWithValues:(const uint32_t [])values + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithValueArray:(GPBUInt32Array *)array; +- (instancetype)initWithCapacity:(NSUInteger)count; + +- (uint32_t)valueAtIndex:(NSUInteger)index; + +- (void)enumerateValuesWithBlock:(void (^)(uint32_t value, NSUInteger idx, BOOL *stop))block; +- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts + usingBlock:(void (^)(uint32_t value, NSUInteger idx, BOOL *stop))block; + +- (void)addValue:(uint32_t)value; +- (void)addValues:(const uint32_t [])values count:(NSUInteger)count; +- (void)addValuesFromArray:(GPBUInt32Array *)array; + +- (void)insertValue:(uint32_t)value atIndex:(NSUInteger)index; + +- (void)replaceValueAtIndex:(NSUInteger)index withValue:(uint32_t)value; + +- (void)removeValueAtIndex:(NSUInteger)index; +- (void)removeAll; + +- (void)exchangeValueAtIndex:(NSUInteger)idx1 + withValueAtIndex:(NSUInteger)idx2; + +@end + +#pragma mark - Int64 + +@interface GPBInt64Array : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)array; ++ (instancetype)arrayWithValue:(int64_t)value; ++ (instancetype)arrayWithValueArray:(GPBInt64Array *)array; ++ (instancetype)arrayWithCapacity:(NSUInteger)count; + +// Initializes the array, copying the values. +- (instancetype)initWithValues:(const int64_t [])values + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithValueArray:(GPBInt64Array *)array; +- (instancetype)initWithCapacity:(NSUInteger)count; + +- (int64_t)valueAtIndex:(NSUInteger)index; + +- (void)enumerateValuesWithBlock:(void (^)(int64_t value, NSUInteger idx, BOOL *stop))block; +- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts + usingBlock:(void (^)(int64_t value, NSUInteger idx, BOOL *stop))block; + +- (void)addValue:(int64_t)value; +- (void)addValues:(const int64_t [])values count:(NSUInteger)count; +- (void)addValuesFromArray:(GPBInt64Array *)array; + +- (void)insertValue:(int64_t)value atIndex:(NSUInteger)index; + +- (void)replaceValueAtIndex:(NSUInteger)index withValue:(int64_t)value; + +- (void)removeValueAtIndex:(NSUInteger)index; +- (void)removeAll; + +- (void)exchangeValueAtIndex:(NSUInteger)idx1 + withValueAtIndex:(NSUInteger)idx2; + +@end + +#pragma mark - UInt64 + +@interface GPBUInt64Array : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)array; ++ (instancetype)arrayWithValue:(uint64_t)value; ++ (instancetype)arrayWithValueArray:(GPBUInt64Array *)array; ++ (instancetype)arrayWithCapacity:(NSUInteger)count; + +// Initializes the array, copying the values. +- (instancetype)initWithValues:(const uint64_t [])values + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithValueArray:(GPBUInt64Array *)array; +- (instancetype)initWithCapacity:(NSUInteger)count; + +- (uint64_t)valueAtIndex:(NSUInteger)index; + +- (void)enumerateValuesWithBlock:(void (^)(uint64_t value, NSUInteger idx, BOOL *stop))block; +- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts + usingBlock:(void (^)(uint64_t value, NSUInteger idx, BOOL *stop))block; + +- (void)addValue:(uint64_t)value; +- (void)addValues:(const uint64_t [])values count:(NSUInteger)count; +- (void)addValuesFromArray:(GPBUInt64Array *)array; + +- (void)insertValue:(uint64_t)value atIndex:(NSUInteger)index; + +- (void)replaceValueAtIndex:(NSUInteger)index withValue:(uint64_t)value; + +- (void)removeValueAtIndex:(NSUInteger)index; +- (void)removeAll; + +- (void)exchangeValueAtIndex:(NSUInteger)idx1 + withValueAtIndex:(NSUInteger)idx2; + +@end + +#pragma mark - Float + +@interface GPBFloatArray : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)array; ++ (instancetype)arrayWithValue:(float)value; ++ (instancetype)arrayWithValueArray:(GPBFloatArray *)array; ++ (instancetype)arrayWithCapacity:(NSUInteger)count; + +// Initializes the array, copying the values. +- (instancetype)initWithValues:(const float [])values + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithValueArray:(GPBFloatArray *)array; +- (instancetype)initWithCapacity:(NSUInteger)count; + +- (float)valueAtIndex:(NSUInteger)index; + +- (void)enumerateValuesWithBlock:(void (^)(float value, NSUInteger idx, BOOL *stop))block; +- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts + usingBlock:(void (^)(float value, NSUInteger idx, BOOL *stop))block; + +- (void)addValue:(float)value; +- (void)addValues:(const float [])values count:(NSUInteger)count; +- (void)addValuesFromArray:(GPBFloatArray *)array; + +- (void)insertValue:(float)value atIndex:(NSUInteger)index; + +- (void)replaceValueAtIndex:(NSUInteger)index withValue:(float)value; + +- (void)removeValueAtIndex:(NSUInteger)index; +- (void)removeAll; + +- (void)exchangeValueAtIndex:(NSUInteger)idx1 + withValueAtIndex:(NSUInteger)idx2; + +@end + +#pragma mark - Double + +@interface GPBDoubleArray : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)array; ++ (instancetype)arrayWithValue:(double)value; ++ (instancetype)arrayWithValueArray:(GPBDoubleArray *)array; ++ (instancetype)arrayWithCapacity:(NSUInteger)count; + +// Initializes the array, copying the values. +- (instancetype)initWithValues:(const double [])values + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithValueArray:(GPBDoubleArray *)array; +- (instancetype)initWithCapacity:(NSUInteger)count; + +- (double)valueAtIndex:(NSUInteger)index; + +- (void)enumerateValuesWithBlock:(void (^)(double value, NSUInteger idx, BOOL *stop))block; +- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts + usingBlock:(void (^)(double value, NSUInteger idx, BOOL *stop))block; + +- (void)addValue:(double)value; +- (void)addValues:(const double [])values count:(NSUInteger)count; +- (void)addValuesFromArray:(GPBDoubleArray *)array; + +- (void)insertValue:(double)value atIndex:(NSUInteger)index; + +- (void)replaceValueAtIndex:(NSUInteger)index withValue:(double)value; + +- (void)removeValueAtIndex:(NSUInteger)index; +- (void)removeAll; + +- (void)exchangeValueAtIndex:(NSUInteger)idx1 + withValueAtIndex:(NSUInteger)idx2; + +@end + +#pragma mark - Bool + +@interface GPBBoolArray : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)array; ++ (instancetype)arrayWithValue:(BOOL)value; ++ (instancetype)arrayWithValueArray:(GPBBoolArray *)array; ++ (instancetype)arrayWithCapacity:(NSUInteger)count; + +// Initializes the array, copying the values. +- (instancetype)initWithValues:(const BOOL [])values + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithValueArray:(GPBBoolArray *)array; +- (instancetype)initWithCapacity:(NSUInteger)count; + +- (BOOL)valueAtIndex:(NSUInteger)index; + +- (void)enumerateValuesWithBlock:(void (^)(BOOL value, NSUInteger idx, BOOL *stop))block; +- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts + usingBlock:(void (^)(BOOL value, NSUInteger idx, BOOL *stop))block; + +- (void)addValue:(BOOL)value; +- (void)addValues:(const BOOL [])values count:(NSUInteger)count; +- (void)addValuesFromArray:(GPBBoolArray *)array; + +- (void)insertValue:(BOOL)value atIndex:(NSUInteger)index; + +- (void)replaceValueAtIndex:(NSUInteger)index withValue:(BOOL)value; + +- (void)removeValueAtIndex:(NSUInteger)index; +- (void)removeAll; + +- (void)exchangeValueAtIndex:(NSUInteger)idx1 + withValueAtIndex:(NSUInteger)idx2; + +@end + +#pragma mark - Enum + +@interface GPBEnumArray : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; +@property(nonatomic, readonly) GPBEnumValidationFunc validationFunc; + ++ (instancetype)array; ++ (instancetype)arrayWithValidationFunction:(GPBEnumValidationFunc)func; ++ (instancetype)arrayWithValidationFunction:(GPBEnumValidationFunc)func + rawValue:(int32_t)value; ++ (instancetype)arrayWithValueArray:(GPBEnumArray *)array; ++ (instancetype)arrayWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)count; + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func; + +// Initializes the array, copying the values. +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])values + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithValueArray:(GPBEnumArray *)array; +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)count; + +// These will return kGPBUnrecognizedEnumeratorValue if the value at index is not a +// valid enumerator as defined by validationFunc. If the actual value is +// desired, use "raw" version of the method. + +- (int32_t)valueAtIndex:(NSUInteger)index; + +- (void)enumerateValuesWithBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block; +- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts + usingBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block; + +// These methods bypass the validationFunc to provide access to values that were not +// known at the time the binary was compiled. + +- (int32_t)rawValueAtIndex:(NSUInteger)index; + +- (void)enumerateRawValuesWithBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block; +- (void)enumerateRawValuesWithOptions:(NSEnumerationOptions)opts + usingBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block; + +// If value is not a valid enumerator as defined by validationFunc, these +// methods will assert in debug, and will log in release and assign the value +// to the default value. Use the rawValue methods below to assign non enumerator +// values. + +- (void)addValue:(int32_t)value; +- (void)addValues:(const int32_t [])values count:(NSUInteger)count; + +- (void)insertValue:(int32_t)value atIndex:(NSUInteger)index; + +- (void)replaceValueAtIndex:(NSUInteger)index withValue:(int32_t)value; + +// These methods bypass the validationFunc to provide setting of values that were not +// known at the time the binary was compiled. + +- (void)addRawValue:(int32_t)value; +- (void)addRawValuesFromArray:(GPBEnumArray *)array; +- (void)addRawValues:(const int32_t [])values count:(NSUInteger)count; + +- (void)insertRawValue:(int32_t)value atIndex:(NSUInteger)index; + +- (void)replaceValueAtIndex:(NSUInteger)index withRawValue:(int32_t)value; + +// No validation applies to these methods. + +- (void)removeValueAtIndex:(NSUInteger)index; +- (void)removeAll; + +- (void)exchangeValueAtIndex:(NSUInteger)idx1 + withValueAtIndex:(NSUInteger)idx2; + +@end + +//%PDDM-EXPAND-END DECLARE_ARRAYS() + +//%PDDM-DEFINE DECLARE_ARRAYS() +//%ARRAY_INTERFACE_SIMPLE(Int32, int32_t) +//%ARRAY_INTERFACE_SIMPLE(UInt32, uint32_t) +//%ARRAY_INTERFACE_SIMPLE(Int64, int64_t) +//%ARRAY_INTERFACE_SIMPLE(UInt64, uint64_t) +//%ARRAY_INTERFACE_SIMPLE(Float, float) +//%ARRAY_INTERFACE_SIMPLE(Double, double) +//%ARRAY_INTERFACE_SIMPLE(Bool, BOOL) +//%ARRAY_INTERFACE_ENUM(Enum, int32_t) + +// +// The common case (everything but Enum) +// + +//%PDDM-DEFINE ARRAY_INTERFACE_SIMPLE(NAME, TYPE) +//%#pragma mark - NAME +//% +//%@interface GPB##NAME##Array : NSObject <NSCopying> +//% +//%@property(nonatomic, readonly) NSUInteger count; +//% +//%+ (instancetype)array; +//%+ (instancetype)arrayWithValue:(TYPE)value; +//%+ (instancetype)arrayWithValueArray:(GPB##NAME##Array *)array; +//%+ (instancetype)arrayWithCapacity:(NSUInteger)count; +//% +//%// Initializes the array, copying the values. +//%- (instancetype)initWithValues:(const TYPE [])values +//% count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +//%- (instancetype)initWithValueArray:(GPB##NAME##Array *)array; +//%- (instancetype)initWithCapacity:(NSUInteger)count; +//% +//%ARRAY_IMMUTABLE_INTERFACE(NAME, TYPE, Basic) +//% +//%ARRAY_MUTABLE_INTERFACE(NAME, TYPE, Basic) +//% +//%@end +//% + +// +// Macros specific to Enums (to tweak their interface). +// + +//%PDDM-DEFINE ARRAY_INTERFACE_ENUM(NAME, TYPE) +//%#pragma mark - NAME +//% +//%@interface GPB##NAME##Array : NSObject <NSCopying> +//% +//%@property(nonatomic, readonly) NSUInteger count; +//%@property(nonatomic, readonly) GPBEnumValidationFunc validationFunc; +//% +//%+ (instancetype)array; +//%+ (instancetype)arrayWithValidationFunction:(GPBEnumValidationFunc)func; +//%+ (instancetype)arrayWithValidationFunction:(GPBEnumValidationFunc)func +//% rawValue:(TYPE)value; +//%+ (instancetype)arrayWithValueArray:(GPB##NAME##Array *)array; +//%+ (instancetype)arrayWithValidationFunction:(GPBEnumValidationFunc)func +//% capacity:(NSUInteger)count; +//% +//%- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func; +//% +//%// Initializes the array, copying the values. +//%- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func +//% rawValues:(const TYPE [])values +//% count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +//%- (instancetype)initWithValueArray:(GPB##NAME##Array *)array; +//%- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func +//% capacity:(NSUInteger)count; +//% +//%// These will return kGPBUnrecognizedEnumeratorValue if the value at index is not a +//%// valid enumerator as defined by validationFunc. If the actual value is +//%// desired, use "raw" version of the method. +//% +//%ARRAY_IMMUTABLE_INTERFACE(NAME, TYPE, NAME) +//% +//%// These methods bypass the validationFunc to provide access to values that were not +//%// known at the time the binary was compiled. +//% +//%- (TYPE)rawValueAtIndex:(NSUInteger)index; +//% +//%- (void)enumerateRawValuesWithBlock:(void (^)(TYPE value, NSUInteger idx, BOOL *stop))block; +//%- (void)enumerateRawValuesWithOptions:(NSEnumerationOptions)opts +//% usingBlock:(void (^)(TYPE value, NSUInteger idx, BOOL *stop))block; +//% +//%// If value is not a valid enumerator as defined by validationFunc, these +//%// methods will assert in debug, and will log in release and assign the value +//%// to the default value. Use the rawValue methods below to assign non enumerator +//%// values. +//% +//%ARRAY_MUTABLE_INTERFACE(NAME, TYPE, NAME) +//% +//%@end +//% + +//%PDDM-DEFINE ARRAY_IMMUTABLE_INTERFACE(NAME, TYPE, HELPER_NAME) +//%- (TYPE)valueAtIndex:(NSUInteger)index; +//% +//%- (void)enumerateValuesWithBlock:(void (^)(TYPE value, NSUInteger idx, BOOL *stop))block; +//%- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts +//% usingBlock:(void (^)(TYPE value, NSUInteger idx, BOOL *stop))block; + +//%PDDM-DEFINE ARRAY_MUTABLE_INTERFACE(NAME, TYPE, HELPER_NAME) +//%- (void)addValue:(TYPE)value; +//%- (void)addValues:(const TYPE [])values count:(NSUInteger)count; +//%ARRAY_EXTRA_MUTABLE_METHODS1_##HELPER_NAME(NAME, TYPE) +//%- (void)insertValue:(TYPE)value atIndex:(NSUInteger)index; +//% +//%- (void)replaceValueAtIndex:(NSUInteger)index withValue:(TYPE)value; +//%ARRAY_EXTRA_MUTABLE_METHODS2_##HELPER_NAME(NAME, TYPE) +//%- (void)removeValueAtIndex:(NSUInteger)index; +//%- (void)removeAll; +//% +//%- (void)exchangeValueAtIndex:(NSUInteger)idx1 +//% withValueAtIndex:(NSUInteger)idx2; + +// +// These are hooks invoked by the above to do insert as needed. +// + +//%PDDM-DEFINE ARRAY_EXTRA_MUTABLE_METHODS1_Basic(NAME, TYPE) +//%- (void)addValuesFromArray:(GPB##NAME##Array *)array; +//% +//%PDDM-DEFINE ARRAY_EXTRA_MUTABLE_METHODS2_Basic(NAME, TYPE) +// Empty +//%PDDM-DEFINE ARRAY_EXTRA_MUTABLE_METHODS1_Enum(NAME, TYPE) +// Empty +//%PDDM-DEFINE ARRAY_EXTRA_MUTABLE_METHODS2_Enum(NAME, TYPE) +//% +//%// These methods bypass the validationFunc to provide setting of values that were not +//%// known at the time the binary was compiled. +//% +//%- (void)addRawValue:(TYPE)value; +//%- (void)addRawValuesFromArray:(GPB##NAME##Array *)array; +//%- (void)addRawValues:(const TYPE [])values count:(NSUInteger)count; +//% +//%- (void)insertRawValue:(TYPE)value atIndex:(NSUInteger)index; +//% +//%- (void)replaceValueAtIndex:(NSUInteger)index withRawValue:(TYPE)value; +//% +//%// No validation applies to these methods. +//% diff --git a/objectivec/GPBArray.m b/objectivec/GPBArray.m new file mode 100644 index 00000000..6aa3df2e --- /dev/null +++ b/objectivec/GPBArray.m @@ -0,0 +1,2499 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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. + +#import "GPBArray_PackagePrivate.h" + +#import "GPBMessage_PackagePrivate.h" + +// Mutable arrays use an internal buffer that can always hold a multiple of this elements. +#define kChunkSize 16 +#define CapacityFromCount(x) (((x / kChunkSize) + 1) * kChunkSize) + +static BOOL ArrayDefault_IsValidValue(int32_t value) { + // Anything but the bad value marker is allowed. + return (value != kGPBUnrecognizedEnumeratorValue); +} + +//%PDDM-DEFINE VALIDATE_RANGE(INDEX, COUNT) +//% if (INDEX >= COUNT) { +//% [NSException raise:NSRangeException +//% format:@"Index (%lu) beyond bounds (%lu)", +//% (unsigned long)INDEX, (unsigned long)COUNT]; +//% } +//%PDDM-DEFINE MAYBE_GROW_TO_SET_COUNT(NEW_COUNT) +//% if (NEW_COUNT > _capacity) { +//% [self internalResizeToCapacity:CapacityFromCount(NEW_COUNT)]; +//% } +//% _count = NEW_COUNT; +//%PDDM-DEFINE SET_COUNT_AND_MAYBE_SHRINK(NEW_COUNT) +//% _count = NEW_COUNT; +//% if ((NEW_COUNT + (2 * kChunkSize)) < _capacity) { +//% [self internalResizeToCapacity:CapacityFromCount(NEW_COUNT)]; +//% } + +// +// Macros for the common basic cases. +// + +//%PDDM-DEFINE ARRAY_INTERFACE_SIMPLE(NAME, TYPE, FORMAT) +//%#pragma mark - NAME +//% +//%@implementation GPB##NAME##Array { +//% @package +//% TYPE *_values; +//% NSUInteger _count; +//% NSUInteger _capacity; +//%} +//% +//%@synthesize count = _count; +//% +//%+ (instancetype)array { +//% return [[[self alloc] initWithValues:NULL count:0] autorelease]; +//%} +//% +//%+ (instancetype)arrayWithValue:(TYPE)value { +//% // Cast is needed so the compiler knows what class we are invoking initWithValues: on to get +//% // the type correct. +//% return [[(GPB##NAME##Array*)[self alloc] initWithValues:&value count:1] autorelease]; +//%} +//% +//%+ (instancetype)arrayWithValueArray:(GPB##NAME##Array *)array { +//% return [[(GPB##NAME##Array*)[self alloc] initWithValueArray:array] autorelease]; +//%} +//% +//%+ (instancetype)arrayWithCapacity:(NSUInteger)count { +//% return [[[self alloc] initWithCapacity:count] autorelease]; +//%} +//% +//%- (instancetype)init { +//% return [self initWithValues:NULL count:0]; +//%} +//% +//%- (instancetype)initWithValueArray:(GPB##NAME##Array *)array { +//% return [self initWithValues:array->_values count:array->_count]; +//%} +//% +//%- (instancetype)initWithValues:(const TYPE [])values count:(NSUInteger)count { +//% self = [super init]; +//% if (self) { +//% if (count && values) { +//% _values = malloc(count * sizeof(TYPE)); +//% if (values != NULL) { +//% _capacity = count; +//% memcpy(_values, values, count * sizeof(TYPE)); +//% _count = count; +//% } else { +//% [self release]; +//% [NSException raise:NSMallocException +//% format:@"Failed to allocate %lu bytes", +//% (unsigned long)(count * sizeof(TYPE))]; +//% } +//% } +//% } +//% return self; +//%} +//% +//%- (instancetype)initWithCapacity:(NSUInteger)count { +//% self = [self initWithValues:NULL count:0]; +//% if (self && count) { +//% [self internalResizeToCapacity:count]; +//% } +//% return self; +//%} +//% +//%- (instancetype)copyWithZone:(NSZone *)zone { +//% return [[GPB##NAME##Array allocWithZone:zone] initWithValues:_values count:_count]; +//%} +//% +//%ARRAY_IMMUTABLE_CORE(NAME, TYPE, , FORMAT) +//% +//%- (TYPE)valueAtIndex:(NSUInteger)index { +//%VALIDATE_RANGE(index, _count) +//% return _values[index]; +//%} +//% +//%ARRAY_MUTABLE_CORE(NAME, TYPE, , FORMAT) +//%@end +//% + +// +// Some core macros used for both the simple types and Enums. +// + +//%PDDM-DEFINE ARRAY_IMMUTABLE_CORE(NAME, TYPE, ACCESSOR_NAME, FORMAT) +//%- (void)dealloc { +//% NSAssert(!_autocreator, @"Autocreator must be cleared before release."); +//% free(_values); +//% [super dealloc]; +//%} +//% +//%- (BOOL)isEqual:(GPB##NAME##Array *)other { +//% if (self == other) { +//% return YES; +//% } +//% if (![other isKindOfClass:[GPB##NAME##Array class]]) { +//% return NO; +//% } +//% return (_count == other->_count +//% && memcmp(_values, other->_values, (_count * sizeof(TYPE))) == 0); +//%} +//% +//%- (NSUInteger)hash { +//% // Follow NSArray's lead, and use the count as the hash. +//% return _count; +//%} +//% +//%- (NSString *)description { +//% NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> { ", [self class], self]; +//% for (NSUInteger i = 0, count = _count; i < count; ++i) { +//% if (i == 0) { +//% [result appendFormat:@"##FORMAT##", _values[i]]; +//% } else { +//% [result appendFormat:@", ##FORMAT##", _values[i]]; +//% } +//% } +//% [result appendFormat:@" }"]; +//% return result; +//%} +//% +//%- (void)enumerate##ACCESSOR_NAME##ValuesWithBlock:(void (^)(TYPE value, NSUInteger idx, BOOL *stop))block { +//% [self enumerate##ACCESSOR_NAME##ValuesWithOptions:0 usingBlock:block]; +//%} +//% +//%- (void)enumerate##ACCESSOR_NAME##ValuesWithOptions:(NSEnumerationOptions)opts +//% ACCESSOR_NAME$S usingBlock:(void (^)(TYPE value, NSUInteger idx, BOOL *stop))block { +//% // NSEnumerationConcurrent isn't currently supported (and Apple's docs say that is ok). +//% BOOL stop = NO; +//% if ((opts & NSEnumerationReverse) == 0) { +//% for (NSUInteger i = 0, count = _count; i < count; ++i) { +//% block(_values[i], i, &stop); +//% if (stop) break; +//% } +//% } else if (_count > 0) { +//% for (NSUInteger i = _count; i > 0; --i) { +//% block(_values[i - 1], (i - 1), &stop); +//% if (stop) break; +//% } +//% } +//%} + +//%PDDM-DEFINE MUTATION_HOOK_None() +//%PDDM-DEFINE MUTATION_METHODS(NAME, TYPE, ACCESSOR_NAME, HOOK_1, HOOK_2) +//%- (void)add##ACCESSOR_NAME##Value:(TYPE)value { +//% [self add##ACCESSOR_NAME##Values:&value count:1]; +//%} +//% +//%- (void)add##ACCESSOR_NAME##Values:(const TYPE [])values count:(NSUInteger)count { +//% if (values == NULL || count == 0) return; +//%MUTATION_HOOK_##HOOK_1() NSUInteger initialCount = _count; +//% NSUInteger newCount = initialCount + count; +//%MAYBE_GROW_TO_SET_COUNT(newCount); +//% memcpy(&_values[initialCount], values, count * sizeof(TYPE)); +//% if (_autocreator) { +//% GPBAutocreatedArrayModified(_autocreator, self); +//% } +//%} +//% +//%- (void)insert##ACCESSOR_NAME##Value:(TYPE)value atIndex:(NSUInteger)index { +//%VALIDATE_RANGE(index, _count + 1) +//%MUTATION_HOOK_##HOOK_2() NSUInteger initialCount = _count; +//% NSUInteger newCount = initialCount + 1; +//%MAYBE_GROW_TO_SET_COUNT(newCount); +//% if (index != initialCount) { +//% memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(TYPE)); +//% } +//% _values[index] = value; +//% if (_autocreator) { +//% GPBAutocreatedArrayModified(_autocreator, self); +//% } +//%} +//% +//%- (void)replaceValueAtIndex:(NSUInteger)index with##ACCESSOR_NAME##Value:(TYPE)value { +//%VALIDATE_RANGE(index, _count) +//%MUTATION_HOOK_##HOOK_2() _values[index] = value; +//%} + +//%PDDM-DEFINE ARRAY_MUTABLE_CORE(NAME, TYPE, ACCESSOR_NAME, FORMAT) +//%- (void)internalResizeToCapacity:(NSUInteger)newCapacity { +//% _values = reallocf(_values, newCapacity * sizeof(TYPE)); +//% if (_values == NULL) { +//% _capacity = 0; +//% _count = 0; +//% [NSException raise:NSMallocException +//% format:@"Failed to allocate %lu bytes", +//% (unsigned long)(newCapacity * sizeof(TYPE))]; +//% } +//% _capacity = newCapacity; +//%} +//% +//%MUTATION_METHODS(NAME, TYPE, ACCESSOR_NAME, None, None) +//% +//%- (void)add##ACCESSOR_NAME##ValuesFromArray:(GPB##NAME##Array *)array { +//% [self add##ACCESSOR_NAME##Values:array->_values count:array->_count]; +//%} +//% +//%- (void)removeValueAtIndex:(NSUInteger)index { +//%VALIDATE_RANGE(index, _count) +//% NSUInteger newCount = _count - 1; +//% if (index != newCount) { +//% memmove(&_values[index], &_values[index + 1], (newCount - index) * sizeof(TYPE)); +//% } +//%SET_COUNT_AND_MAYBE_SHRINK(newCount) +//%} +//% +//%- (void)removeAll { +//%SET_COUNT_AND_MAYBE_SHRINK(0) +//%} +//% +//%- (void)exchangeValueAtIndex:(NSUInteger)idx1 +//% withValueAtIndex:(NSUInteger)idx2 { +//%VALIDATE_RANGE(idx1, _count) +//%VALIDATE_RANGE(idx2, _count) +//% TYPE temp = _values[idx1]; +//% _values[idx1] = _values[idx2]; +//% _values[idx2] = temp; +//%} +//% + +//%PDDM-EXPAND ARRAY_INTERFACE_SIMPLE(Int32, int32_t, %d) +// This block of code is generated, do not edit it directly. + +#pragma mark - Int32 + +@implementation GPBInt32Array { + @package + int32_t *_values; + NSUInteger _count; + NSUInteger _capacity; +} + +@synthesize count = _count; + ++ (instancetype)array { + return [[[self alloc] initWithValues:NULL count:0] autorelease]; +} + ++ (instancetype)arrayWithValue:(int32_t)value { + // Cast is needed so the compiler knows what class we are invoking initWithValues: on to get + // the type correct. + return [[(GPBInt32Array*)[self alloc] initWithValues:&value count:1] autorelease]; +} + ++ (instancetype)arrayWithValueArray:(GPBInt32Array *)array { + return [[(GPBInt32Array*)[self alloc] initWithValueArray:array] autorelease]; +} + ++ (instancetype)arrayWithCapacity:(NSUInteger)count { + return [[[self alloc] initWithCapacity:count] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL count:0]; +} + +- (instancetype)initWithValueArray:(GPBInt32Array *)array { + return [self initWithValues:array->_values count:array->_count]; +} + +- (instancetype)initWithValues:(const int32_t [])values count:(NSUInteger)count { + self = [super init]; + if (self) { + if (count && values) { + _values = malloc(count * sizeof(int32_t)); + if (values != NULL) { + _capacity = count; + memcpy(_values, values, count * sizeof(int32_t)); + _count = count; + } else { + [self release]; + [NSException raise:NSMallocException + format:@"Failed to allocate %lu bytes", + (unsigned long)(count * sizeof(int32_t))]; + } + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)count { + self = [self initWithValues:NULL count:0]; + if (self && count) { + [self internalResizeToCapacity:count]; + } + return self; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBInt32Array allocWithZone:zone] initWithValues:_values count:_count]; +} + +- (void)dealloc { + NSAssert(!_autocreator, @"Autocreator must be cleared before release."); + free(_values); + [super dealloc]; +} + +- (BOOL)isEqual:(GPBInt32Array *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBInt32Array class]]) { + return NO; + } + return (_count == other->_count + && memcmp(_values, other->_values, (_count * sizeof(int32_t))) == 0); +} + +- (NSUInteger)hash { + // Follow NSArray's lead, and use the count as the hash. + return _count; +} + +- (NSString *)description { + NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> { ", [self class], self]; + for (NSUInteger i = 0, count = _count; i < count; ++i) { + if (i == 0) { + [result appendFormat:@"%d", _values[i]]; + } else { + [result appendFormat:@", %d", _values[i]]; + } + } + [result appendFormat:@" }"]; + return result; +} + +- (void)enumerateValuesWithBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block { + [self enumerateValuesWithOptions:0 usingBlock:block]; +} + +- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts + usingBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block { + // NSEnumerationConcurrent isn't currently supported (and Apple's docs say that is ok). + BOOL stop = NO; + if ((opts & NSEnumerationReverse) == 0) { + for (NSUInteger i = 0, count = _count; i < count; ++i) { + block(_values[i], i, &stop); + if (stop) break; + } + } else if (_count > 0) { + for (NSUInteger i = _count; i > 0; --i) { + block(_values[i - 1], (i - 1), &stop); + if (stop) break; + } + } +} + +- (int32_t)valueAtIndex:(NSUInteger)index { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + return _values[index]; +} + +- (void)internalResizeToCapacity:(NSUInteger)newCapacity { + _values = reallocf(_values, newCapacity * sizeof(int32_t)); + if (_values == NULL) { + _capacity = 0; + _count = 0; + [NSException raise:NSMallocException + format:@"Failed to allocate %lu bytes", + (unsigned long)(newCapacity * sizeof(int32_t))]; + } + _capacity = newCapacity; +} + +- (void)addValue:(int32_t)value { + [self addValues:&value count:1]; +} + +- (void)addValues:(const int32_t [])values count:(NSUInteger)count { + if (values == NULL || count == 0) return; + NSUInteger initialCount = _count; + NSUInteger newCount = initialCount + count; + if (newCount > _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } + _count = newCount;; + memcpy(&_values[initialCount], values, count * sizeof(int32_t)); + if (_autocreator) { + GPBAutocreatedArrayModified(_autocreator, self); + } +} + +- (void)insertValue:(int32_t)value atIndex:(NSUInteger)index { + if (index >= _count + 1) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count + 1]; + } + NSUInteger initialCount = _count; + NSUInteger newCount = initialCount + 1; + if (newCount > _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } + _count = newCount;; + if (index != initialCount) { + memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(int32_t)); + } + _values[index] = value; + if (_autocreator) { + GPBAutocreatedArrayModified(_autocreator, self); + } +} + +- (void)replaceValueAtIndex:(NSUInteger)index withValue:(int32_t)value { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + _values[index] = value; +} + +- (void)addValuesFromArray:(GPBInt32Array *)array { + [self addValues:array->_values count:array->_count]; +} + +- (void)removeValueAtIndex:(NSUInteger)index { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + NSUInteger newCount = _count - 1; + if (index != newCount) { + memmove(&_values[index], &_values[index + 1], (newCount - index) * sizeof(int32_t)); + } + _count = newCount; + if ((newCount + (2 * kChunkSize)) < _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } +} + +- (void)removeAll { + _count = 0; + if ((0 + (2 * kChunkSize)) < _capacity) { + [self internalResizeToCapacity:CapacityFromCount(0)]; + } +} + +- (void)exchangeValueAtIndex:(NSUInteger)idx1 + withValueAtIndex:(NSUInteger)idx2 { + if (idx1 >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)idx1, (unsigned long)_count]; + } + if (idx2 >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)idx2, (unsigned long)_count]; + } + int32_t temp = _values[idx1]; + _values[idx1] = _values[idx2]; + _values[idx2] = temp; +} + +@end + +//%PDDM-EXPAND ARRAY_INTERFACE_SIMPLE(UInt32, uint32_t, %u) +// This block of code is generated, do not edit it directly. + +#pragma mark - UInt32 + +@implementation GPBUInt32Array { + @package + uint32_t *_values; + NSUInteger _count; + NSUInteger _capacity; +} + +@synthesize count = _count; + ++ (instancetype)array { + return [[[self alloc] initWithValues:NULL count:0] autorelease]; +} + ++ (instancetype)arrayWithValue:(uint32_t)value { + // Cast is needed so the compiler knows what class we are invoking initWithValues: on to get + // the type correct. + return [[(GPBUInt32Array*)[self alloc] initWithValues:&value count:1] autorelease]; +} + ++ (instancetype)arrayWithValueArray:(GPBUInt32Array *)array { + return [[(GPBUInt32Array*)[self alloc] initWithValueArray:array] autorelease]; +} + ++ (instancetype)arrayWithCapacity:(NSUInteger)count { + return [[[self alloc] initWithCapacity:count] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL count:0]; +} + +- (instancetype)initWithValueArray:(GPBUInt32Array *)array { + return [self initWithValues:array->_values count:array->_count]; +} + +- (instancetype)initWithValues:(const uint32_t [])values count:(NSUInteger)count { + self = [super init]; + if (self) { + if (count && values) { + _values = malloc(count * sizeof(uint32_t)); + if (values != NULL) { + _capacity = count; + memcpy(_values, values, count * sizeof(uint32_t)); + _count = count; + } else { + [self release]; + [NSException raise:NSMallocException + format:@"Failed to allocate %lu bytes", + (unsigned long)(count * sizeof(uint32_t))]; + } + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)count { + self = [self initWithValues:NULL count:0]; + if (self && count) { + [self internalResizeToCapacity:count]; + } + return self; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBUInt32Array allocWithZone:zone] initWithValues:_values count:_count]; +} + +- (void)dealloc { + NSAssert(!_autocreator, @"Autocreator must be cleared before release."); + free(_values); + [super dealloc]; +} + +- (BOOL)isEqual:(GPBUInt32Array *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBUInt32Array class]]) { + return NO; + } + return (_count == other->_count + && memcmp(_values, other->_values, (_count * sizeof(uint32_t))) == 0); +} + +- (NSUInteger)hash { + // Follow NSArray's lead, and use the count as the hash. + return _count; +} + +- (NSString *)description { + NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> { ", [self class], self]; + for (NSUInteger i = 0, count = _count; i < count; ++i) { + if (i == 0) { + [result appendFormat:@"%u", _values[i]]; + } else { + [result appendFormat:@", %u", _values[i]]; + } + } + [result appendFormat:@" }"]; + return result; +} + +- (void)enumerateValuesWithBlock:(void (^)(uint32_t value, NSUInteger idx, BOOL *stop))block { + [self enumerateValuesWithOptions:0 usingBlock:block]; +} + +- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts + usingBlock:(void (^)(uint32_t value, NSUInteger idx, BOOL *stop))block { + // NSEnumerationConcurrent isn't currently supported (and Apple's docs say that is ok). + BOOL stop = NO; + if ((opts & NSEnumerationReverse) == 0) { + for (NSUInteger i = 0, count = _count; i < count; ++i) { + block(_values[i], i, &stop); + if (stop) break; + } + } else if (_count > 0) { + for (NSUInteger i = _count; i > 0; --i) { + block(_values[i - 1], (i - 1), &stop); + if (stop) break; + } + } +} + +- (uint32_t)valueAtIndex:(NSUInteger)index { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + return _values[index]; +} + +- (void)internalResizeToCapacity:(NSUInteger)newCapacity { + _values = reallocf(_values, newCapacity * sizeof(uint32_t)); + if (_values == NULL) { + _capacity = 0; + _count = 0; + [NSException raise:NSMallocException + format:@"Failed to allocate %lu bytes", + (unsigned long)(newCapacity * sizeof(uint32_t))]; + } + _capacity = newCapacity; +} + +- (void)addValue:(uint32_t)value { + [self addValues:&value count:1]; +} + +- (void)addValues:(const uint32_t [])values count:(NSUInteger)count { + if (values == NULL || count == 0) return; + NSUInteger initialCount = _count; + NSUInteger newCount = initialCount + count; + if (newCount > _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } + _count = newCount;; + memcpy(&_values[initialCount], values, count * sizeof(uint32_t)); + if (_autocreator) { + GPBAutocreatedArrayModified(_autocreator, self); + } +} + +- (void)insertValue:(uint32_t)value atIndex:(NSUInteger)index { + if (index >= _count + 1) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count + 1]; + } + NSUInteger initialCount = _count; + NSUInteger newCount = initialCount + 1; + if (newCount > _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } + _count = newCount;; + if (index != initialCount) { + memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(uint32_t)); + } + _values[index] = value; + if (_autocreator) { + GPBAutocreatedArrayModified(_autocreator, self); + } +} + +- (void)replaceValueAtIndex:(NSUInteger)index withValue:(uint32_t)value { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + _values[index] = value; +} + +- (void)addValuesFromArray:(GPBUInt32Array *)array { + [self addValues:array->_values count:array->_count]; +} + +- (void)removeValueAtIndex:(NSUInteger)index { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + NSUInteger newCount = _count - 1; + if (index != newCount) { + memmove(&_values[index], &_values[index + 1], (newCount - index) * sizeof(uint32_t)); + } + _count = newCount; + if ((newCount + (2 * kChunkSize)) < _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } +} + +- (void)removeAll { + _count = 0; + if ((0 + (2 * kChunkSize)) < _capacity) { + [self internalResizeToCapacity:CapacityFromCount(0)]; + } +} + +- (void)exchangeValueAtIndex:(NSUInteger)idx1 + withValueAtIndex:(NSUInteger)idx2 { + if (idx1 >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)idx1, (unsigned long)_count]; + } + if (idx2 >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)idx2, (unsigned long)_count]; + } + uint32_t temp = _values[idx1]; + _values[idx1] = _values[idx2]; + _values[idx2] = temp; +} + +@end + +//%PDDM-EXPAND ARRAY_INTERFACE_SIMPLE(Int64, int64_t, %lld) +// This block of code is generated, do not edit it directly. + +#pragma mark - Int64 + +@implementation GPBInt64Array { + @package + int64_t *_values; + NSUInteger _count; + NSUInteger _capacity; +} + +@synthesize count = _count; + ++ (instancetype)array { + return [[[self alloc] initWithValues:NULL count:0] autorelease]; +} + ++ (instancetype)arrayWithValue:(int64_t)value { + // Cast is needed so the compiler knows what class we are invoking initWithValues: on to get + // the type correct. + return [[(GPBInt64Array*)[self alloc] initWithValues:&value count:1] autorelease]; +} + ++ (instancetype)arrayWithValueArray:(GPBInt64Array *)array { + return [[(GPBInt64Array*)[self alloc] initWithValueArray:array] autorelease]; +} + ++ (instancetype)arrayWithCapacity:(NSUInteger)count { + return [[[self alloc] initWithCapacity:count] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL count:0]; +} + +- (instancetype)initWithValueArray:(GPBInt64Array *)array { + return [self initWithValues:array->_values count:array->_count]; +} + +- (instancetype)initWithValues:(const int64_t [])values count:(NSUInteger)count { + self = [super init]; + if (self) { + if (count && values) { + _values = malloc(count * sizeof(int64_t)); + if (values != NULL) { + _capacity = count; + memcpy(_values, values, count * sizeof(int64_t)); + _count = count; + } else { + [self release]; + [NSException raise:NSMallocException + format:@"Failed to allocate %lu bytes", + (unsigned long)(count * sizeof(int64_t))]; + } + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)count { + self = [self initWithValues:NULL count:0]; + if (self && count) { + [self internalResizeToCapacity:count]; + } + return self; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBInt64Array allocWithZone:zone] initWithValues:_values count:_count]; +} + +- (void)dealloc { + NSAssert(!_autocreator, @"Autocreator must be cleared before release."); + free(_values); + [super dealloc]; +} + +- (BOOL)isEqual:(GPBInt64Array *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBInt64Array class]]) { + return NO; + } + return (_count == other->_count + && memcmp(_values, other->_values, (_count * sizeof(int64_t))) == 0); +} + +- (NSUInteger)hash { + // Follow NSArray's lead, and use the count as the hash. + return _count; +} + +- (NSString *)description { + NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> { ", [self class], self]; + for (NSUInteger i = 0, count = _count; i < count; ++i) { + if (i == 0) { + [result appendFormat:@"%lld", _values[i]]; + } else { + [result appendFormat:@", %lld", _values[i]]; + } + } + [result appendFormat:@" }"]; + return result; +} + +- (void)enumerateValuesWithBlock:(void (^)(int64_t value, NSUInteger idx, BOOL *stop))block { + [self enumerateValuesWithOptions:0 usingBlock:block]; +} + +- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts + usingBlock:(void (^)(int64_t value, NSUInteger idx, BOOL *stop))block { + // NSEnumerationConcurrent isn't currently supported (and Apple's docs say that is ok). + BOOL stop = NO; + if ((opts & NSEnumerationReverse) == 0) { + for (NSUInteger i = 0, count = _count; i < count; ++i) { + block(_values[i], i, &stop); + if (stop) break; + } + } else if (_count > 0) { + for (NSUInteger i = _count; i > 0; --i) { + block(_values[i - 1], (i - 1), &stop); + if (stop) break; + } + } +} + +- (int64_t)valueAtIndex:(NSUInteger)index { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + return _values[index]; +} + +- (void)internalResizeToCapacity:(NSUInteger)newCapacity { + _values = reallocf(_values, newCapacity * sizeof(int64_t)); + if (_values == NULL) { + _capacity = 0; + _count = 0; + [NSException raise:NSMallocException + format:@"Failed to allocate %lu bytes", + (unsigned long)(newCapacity * sizeof(int64_t))]; + } + _capacity = newCapacity; +} + +- (void)addValue:(int64_t)value { + [self addValues:&value count:1]; +} + +- (void)addValues:(const int64_t [])values count:(NSUInteger)count { + if (values == NULL || count == 0) return; + NSUInteger initialCount = _count; + NSUInteger newCount = initialCount + count; + if (newCount > _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } + _count = newCount;; + memcpy(&_values[initialCount], values, count * sizeof(int64_t)); + if (_autocreator) { + GPBAutocreatedArrayModified(_autocreator, self); + } +} + +- (void)insertValue:(int64_t)value atIndex:(NSUInteger)index { + if (index >= _count + 1) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count + 1]; + } + NSUInteger initialCount = _count; + NSUInteger newCount = initialCount + 1; + if (newCount > _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } + _count = newCount;; + if (index != initialCount) { + memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(int64_t)); + } + _values[index] = value; + if (_autocreator) { + GPBAutocreatedArrayModified(_autocreator, self); + } +} + +- (void)replaceValueAtIndex:(NSUInteger)index withValue:(int64_t)value { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + _values[index] = value; +} + +- (void)addValuesFromArray:(GPBInt64Array *)array { + [self addValues:array->_values count:array->_count]; +} + +- (void)removeValueAtIndex:(NSUInteger)index { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + NSUInteger newCount = _count - 1; + if (index != newCount) { + memmove(&_values[index], &_values[index + 1], (newCount - index) * sizeof(int64_t)); + } + _count = newCount; + if ((newCount + (2 * kChunkSize)) < _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } +} + +- (void)removeAll { + _count = 0; + if ((0 + (2 * kChunkSize)) < _capacity) { + [self internalResizeToCapacity:CapacityFromCount(0)]; + } +} + +- (void)exchangeValueAtIndex:(NSUInteger)idx1 + withValueAtIndex:(NSUInteger)idx2 { + if (idx1 >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)idx1, (unsigned long)_count]; + } + if (idx2 >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)idx2, (unsigned long)_count]; + } + int64_t temp = _values[idx1]; + _values[idx1] = _values[idx2]; + _values[idx2] = temp; +} + +@end + +//%PDDM-EXPAND ARRAY_INTERFACE_SIMPLE(UInt64, uint64_t, %llu) +// This block of code is generated, do not edit it directly. + +#pragma mark - UInt64 + +@implementation GPBUInt64Array { + @package + uint64_t *_values; + NSUInteger _count; + NSUInteger _capacity; +} + +@synthesize count = _count; + ++ (instancetype)array { + return [[[self alloc] initWithValues:NULL count:0] autorelease]; +} + ++ (instancetype)arrayWithValue:(uint64_t)value { + // Cast is needed so the compiler knows what class we are invoking initWithValues: on to get + // the type correct. + return [[(GPBUInt64Array*)[self alloc] initWithValues:&value count:1] autorelease]; +} + ++ (instancetype)arrayWithValueArray:(GPBUInt64Array *)array { + return [[(GPBUInt64Array*)[self alloc] initWithValueArray:array] autorelease]; +} + ++ (instancetype)arrayWithCapacity:(NSUInteger)count { + return [[[self alloc] initWithCapacity:count] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL count:0]; +} + +- (instancetype)initWithValueArray:(GPBUInt64Array *)array { + return [self initWithValues:array->_values count:array->_count]; +} + +- (instancetype)initWithValues:(const uint64_t [])values count:(NSUInteger)count { + self = [super init]; + if (self) { + if (count && values) { + _values = malloc(count * sizeof(uint64_t)); + if (values != NULL) { + _capacity = count; + memcpy(_values, values, count * sizeof(uint64_t)); + _count = count; + } else { + [self release]; + [NSException raise:NSMallocException + format:@"Failed to allocate %lu bytes", + (unsigned long)(count * sizeof(uint64_t))]; + } + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)count { + self = [self initWithValues:NULL count:0]; + if (self && count) { + [self internalResizeToCapacity:count]; + } + return self; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBUInt64Array allocWithZone:zone] initWithValues:_values count:_count]; +} + +- (void)dealloc { + NSAssert(!_autocreator, @"Autocreator must be cleared before release."); + free(_values); + [super dealloc]; +} + +- (BOOL)isEqual:(GPBUInt64Array *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBUInt64Array class]]) { + return NO; + } + return (_count == other->_count + && memcmp(_values, other->_values, (_count * sizeof(uint64_t))) == 0); +} + +- (NSUInteger)hash { + // Follow NSArray's lead, and use the count as the hash. + return _count; +} + +- (NSString *)description { + NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> { ", [self class], self]; + for (NSUInteger i = 0, count = _count; i < count; ++i) { + if (i == 0) { + [result appendFormat:@"%llu", _values[i]]; + } else { + [result appendFormat:@", %llu", _values[i]]; + } + } + [result appendFormat:@" }"]; + return result; +} + +- (void)enumerateValuesWithBlock:(void (^)(uint64_t value, NSUInteger idx, BOOL *stop))block { + [self enumerateValuesWithOptions:0 usingBlock:block]; +} + +- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts + usingBlock:(void (^)(uint64_t value, NSUInteger idx, BOOL *stop))block { + // NSEnumerationConcurrent isn't currently supported (and Apple's docs say that is ok). + BOOL stop = NO; + if ((opts & NSEnumerationReverse) == 0) { + for (NSUInteger i = 0, count = _count; i < count; ++i) { + block(_values[i], i, &stop); + if (stop) break; + } + } else if (_count > 0) { + for (NSUInteger i = _count; i > 0; --i) { + block(_values[i - 1], (i - 1), &stop); + if (stop) break; + } + } +} + +- (uint64_t)valueAtIndex:(NSUInteger)index { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + return _values[index]; +} + +- (void)internalResizeToCapacity:(NSUInteger)newCapacity { + _values = reallocf(_values, newCapacity * sizeof(uint64_t)); + if (_values == NULL) { + _capacity = 0; + _count = 0; + [NSException raise:NSMallocException + format:@"Failed to allocate %lu bytes", + (unsigned long)(newCapacity * sizeof(uint64_t))]; + } + _capacity = newCapacity; +} + +- (void)addValue:(uint64_t)value { + [self addValues:&value count:1]; +} + +- (void)addValues:(const uint64_t [])values count:(NSUInteger)count { + if (values == NULL || count == 0) return; + NSUInteger initialCount = _count; + NSUInteger newCount = initialCount + count; + if (newCount > _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } + _count = newCount;; + memcpy(&_values[initialCount], values, count * sizeof(uint64_t)); + if (_autocreator) { + GPBAutocreatedArrayModified(_autocreator, self); + } +} + +- (void)insertValue:(uint64_t)value atIndex:(NSUInteger)index { + if (index >= _count + 1) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count + 1]; + } + NSUInteger initialCount = _count; + NSUInteger newCount = initialCount + 1; + if (newCount > _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } + _count = newCount;; + if (index != initialCount) { + memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(uint64_t)); + } + _values[index] = value; + if (_autocreator) { + GPBAutocreatedArrayModified(_autocreator, self); + } +} + +- (void)replaceValueAtIndex:(NSUInteger)index withValue:(uint64_t)value { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + _values[index] = value; +} + +- (void)addValuesFromArray:(GPBUInt64Array *)array { + [self addValues:array->_values count:array->_count]; +} + +- (void)removeValueAtIndex:(NSUInteger)index { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + NSUInteger newCount = _count - 1; + if (index != newCount) { + memmove(&_values[index], &_values[index + 1], (newCount - index) * sizeof(uint64_t)); + } + _count = newCount; + if ((newCount + (2 * kChunkSize)) < _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } +} + +- (void)removeAll { + _count = 0; + if ((0 + (2 * kChunkSize)) < _capacity) { + [self internalResizeToCapacity:CapacityFromCount(0)]; + } +} + +- (void)exchangeValueAtIndex:(NSUInteger)idx1 + withValueAtIndex:(NSUInteger)idx2 { + if (idx1 >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)idx1, (unsigned long)_count]; + } + if (idx2 >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)idx2, (unsigned long)_count]; + } + uint64_t temp = _values[idx1]; + _values[idx1] = _values[idx2]; + _values[idx2] = temp; +} + +@end + +//%PDDM-EXPAND ARRAY_INTERFACE_SIMPLE(Float, float, %f) +// This block of code is generated, do not edit it directly. + +#pragma mark - Float + +@implementation GPBFloatArray { + @package + float *_values; + NSUInteger _count; + NSUInteger _capacity; +} + +@synthesize count = _count; + ++ (instancetype)array { + return [[[self alloc] initWithValues:NULL count:0] autorelease]; +} + ++ (instancetype)arrayWithValue:(float)value { + // Cast is needed so the compiler knows what class we are invoking initWithValues: on to get + // the type correct. + return [[(GPBFloatArray*)[self alloc] initWithValues:&value count:1] autorelease]; +} + ++ (instancetype)arrayWithValueArray:(GPBFloatArray *)array { + return [[(GPBFloatArray*)[self alloc] initWithValueArray:array] autorelease]; +} + ++ (instancetype)arrayWithCapacity:(NSUInteger)count { + return [[[self alloc] initWithCapacity:count] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL count:0]; +} + +- (instancetype)initWithValueArray:(GPBFloatArray *)array { + return [self initWithValues:array->_values count:array->_count]; +} + +- (instancetype)initWithValues:(const float [])values count:(NSUInteger)count { + self = [super init]; + if (self) { + if (count && values) { + _values = malloc(count * sizeof(float)); + if (values != NULL) { + _capacity = count; + memcpy(_values, values, count * sizeof(float)); + _count = count; + } else { + [self release]; + [NSException raise:NSMallocException + format:@"Failed to allocate %lu bytes", + (unsigned long)(count * sizeof(float))]; + } + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)count { + self = [self initWithValues:NULL count:0]; + if (self && count) { + [self internalResizeToCapacity:count]; + } + return self; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBFloatArray allocWithZone:zone] initWithValues:_values count:_count]; +} + +- (void)dealloc { + NSAssert(!_autocreator, @"Autocreator must be cleared before release."); + free(_values); + [super dealloc]; +} + +- (BOOL)isEqual:(GPBFloatArray *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBFloatArray class]]) { + return NO; + } + return (_count == other->_count + && memcmp(_values, other->_values, (_count * sizeof(float))) == 0); +} + +- (NSUInteger)hash { + // Follow NSArray's lead, and use the count as the hash. + return _count; +} + +- (NSString *)description { + NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> { ", [self class], self]; + for (NSUInteger i = 0, count = _count; i < count; ++i) { + if (i == 0) { + [result appendFormat:@"%f", _values[i]]; + } else { + [result appendFormat:@", %f", _values[i]]; + } + } + [result appendFormat:@" }"]; + return result; +} + +- (void)enumerateValuesWithBlock:(void (^)(float value, NSUInteger idx, BOOL *stop))block { + [self enumerateValuesWithOptions:0 usingBlock:block]; +} + +- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts + usingBlock:(void (^)(float value, NSUInteger idx, BOOL *stop))block { + // NSEnumerationConcurrent isn't currently supported (and Apple's docs say that is ok). + BOOL stop = NO; + if ((opts & NSEnumerationReverse) == 0) { + for (NSUInteger i = 0, count = _count; i < count; ++i) { + block(_values[i], i, &stop); + if (stop) break; + } + } else if (_count > 0) { + for (NSUInteger i = _count; i > 0; --i) { + block(_values[i - 1], (i - 1), &stop); + if (stop) break; + } + } +} + +- (float)valueAtIndex:(NSUInteger)index { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + return _values[index]; +} + +- (void)internalResizeToCapacity:(NSUInteger)newCapacity { + _values = reallocf(_values, newCapacity * sizeof(float)); + if (_values == NULL) { + _capacity = 0; + _count = 0; + [NSException raise:NSMallocException + format:@"Failed to allocate %lu bytes", + (unsigned long)(newCapacity * sizeof(float))]; + } + _capacity = newCapacity; +} + +- (void)addValue:(float)value { + [self addValues:&value count:1]; +} + +- (void)addValues:(const float [])values count:(NSUInteger)count { + if (values == NULL || count == 0) return; + NSUInteger initialCount = _count; + NSUInteger newCount = initialCount + count; + if (newCount > _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } + _count = newCount;; + memcpy(&_values[initialCount], values, count * sizeof(float)); + if (_autocreator) { + GPBAutocreatedArrayModified(_autocreator, self); + } +} + +- (void)insertValue:(float)value atIndex:(NSUInteger)index { + if (index >= _count + 1) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count + 1]; + } + NSUInteger initialCount = _count; + NSUInteger newCount = initialCount + 1; + if (newCount > _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } + _count = newCount;; + if (index != initialCount) { + memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(float)); + } + _values[index] = value; + if (_autocreator) { + GPBAutocreatedArrayModified(_autocreator, self); + } +} + +- (void)replaceValueAtIndex:(NSUInteger)index withValue:(float)value { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + _values[index] = value; +} + +- (void)addValuesFromArray:(GPBFloatArray *)array { + [self addValues:array->_values count:array->_count]; +} + +- (void)removeValueAtIndex:(NSUInteger)index { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + NSUInteger newCount = _count - 1; + if (index != newCount) { + memmove(&_values[index], &_values[index + 1], (newCount - index) * sizeof(float)); + } + _count = newCount; + if ((newCount + (2 * kChunkSize)) < _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } +} + +- (void)removeAll { + _count = 0; + if ((0 + (2 * kChunkSize)) < _capacity) { + [self internalResizeToCapacity:CapacityFromCount(0)]; + } +} + +- (void)exchangeValueAtIndex:(NSUInteger)idx1 + withValueAtIndex:(NSUInteger)idx2 { + if (idx1 >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)idx1, (unsigned long)_count]; + } + if (idx2 >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)idx2, (unsigned long)_count]; + } + float temp = _values[idx1]; + _values[idx1] = _values[idx2]; + _values[idx2] = temp; +} + +@end + +//%PDDM-EXPAND ARRAY_INTERFACE_SIMPLE(Double, double, %lf) +// This block of code is generated, do not edit it directly. + +#pragma mark - Double + +@implementation GPBDoubleArray { + @package + double *_values; + NSUInteger _count; + NSUInteger _capacity; +} + +@synthesize count = _count; + ++ (instancetype)array { + return [[[self alloc] initWithValues:NULL count:0] autorelease]; +} + ++ (instancetype)arrayWithValue:(double)value { + // Cast is needed so the compiler knows what class we are invoking initWithValues: on to get + // the type correct. + return [[(GPBDoubleArray*)[self alloc] initWithValues:&value count:1] autorelease]; +} + ++ (instancetype)arrayWithValueArray:(GPBDoubleArray *)array { + return [[(GPBDoubleArray*)[self alloc] initWithValueArray:array] autorelease]; +} + ++ (instancetype)arrayWithCapacity:(NSUInteger)count { + return [[[self alloc] initWithCapacity:count] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL count:0]; +} + +- (instancetype)initWithValueArray:(GPBDoubleArray *)array { + return [self initWithValues:array->_values count:array->_count]; +} + +- (instancetype)initWithValues:(const double [])values count:(NSUInteger)count { + self = [super init]; + if (self) { + if (count && values) { + _values = malloc(count * sizeof(double)); + if (values != NULL) { + _capacity = count; + memcpy(_values, values, count * sizeof(double)); + _count = count; + } else { + [self release]; + [NSException raise:NSMallocException + format:@"Failed to allocate %lu bytes", + (unsigned long)(count * sizeof(double))]; + } + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)count { + self = [self initWithValues:NULL count:0]; + if (self && count) { + [self internalResizeToCapacity:count]; + } + return self; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBDoubleArray allocWithZone:zone] initWithValues:_values count:_count]; +} + +- (void)dealloc { + NSAssert(!_autocreator, @"Autocreator must be cleared before release."); + free(_values); + [super dealloc]; +} + +- (BOOL)isEqual:(GPBDoubleArray *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBDoubleArray class]]) { + return NO; + } + return (_count == other->_count + && memcmp(_values, other->_values, (_count * sizeof(double))) == 0); +} + +- (NSUInteger)hash { + // Follow NSArray's lead, and use the count as the hash. + return _count; +} + +- (NSString *)description { + NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> { ", [self class], self]; + for (NSUInteger i = 0, count = _count; i < count; ++i) { + if (i == 0) { + [result appendFormat:@"%lf", _values[i]]; + } else { + [result appendFormat:@", %lf", _values[i]]; + } + } + [result appendFormat:@" }"]; + return result; +} + +- (void)enumerateValuesWithBlock:(void (^)(double value, NSUInteger idx, BOOL *stop))block { + [self enumerateValuesWithOptions:0 usingBlock:block]; +} + +- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts + usingBlock:(void (^)(double value, NSUInteger idx, BOOL *stop))block { + // NSEnumerationConcurrent isn't currently supported (and Apple's docs say that is ok). + BOOL stop = NO; + if ((opts & NSEnumerationReverse) == 0) { + for (NSUInteger i = 0, count = _count; i < count; ++i) { + block(_values[i], i, &stop); + if (stop) break; + } + } else if (_count > 0) { + for (NSUInteger i = _count; i > 0; --i) { + block(_values[i - 1], (i - 1), &stop); + if (stop) break; + } + } +} + +- (double)valueAtIndex:(NSUInteger)index { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + return _values[index]; +} + +- (void)internalResizeToCapacity:(NSUInteger)newCapacity { + _values = reallocf(_values, newCapacity * sizeof(double)); + if (_values == NULL) { + _capacity = 0; + _count = 0; + [NSException raise:NSMallocException + format:@"Failed to allocate %lu bytes", + (unsigned long)(newCapacity * sizeof(double))]; + } + _capacity = newCapacity; +} + +- (void)addValue:(double)value { + [self addValues:&value count:1]; +} + +- (void)addValues:(const double [])values count:(NSUInteger)count { + if (values == NULL || count == 0) return; + NSUInteger initialCount = _count; + NSUInteger newCount = initialCount + count; + if (newCount > _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } + _count = newCount;; + memcpy(&_values[initialCount], values, count * sizeof(double)); + if (_autocreator) { + GPBAutocreatedArrayModified(_autocreator, self); + } +} + +- (void)insertValue:(double)value atIndex:(NSUInteger)index { + if (index >= _count + 1) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count + 1]; + } + NSUInteger initialCount = _count; + NSUInteger newCount = initialCount + 1; + if (newCount > _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } + _count = newCount;; + if (index != initialCount) { + memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(double)); + } + _values[index] = value; + if (_autocreator) { + GPBAutocreatedArrayModified(_autocreator, self); + } +} + +- (void)replaceValueAtIndex:(NSUInteger)index withValue:(double)value { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + _values[index] = value; +} + +- (void)addValuesFromArray:(GPBDoubleArray *)array { + [self addValues:array->_values count:array->_count]; +} + +- (void)removeValueAtIndex:(NSUInteger)index { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + NSUInteger newCount = _count - 1; + if (index != newCount) { + memmove(&_values[index], &_values[index + 1], (newCount - index) * sizeof(double)); + } + _count = newCount; + if ((newCount + (2 * kChunkSize)) < _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } +} + +- (void)removeAll { + _count = 0; + if ((0 + (2 * kChunkSize)) < _capacity) { + [self internalResizeToCapacity:CapacityFromCount(0)]; + } +} + +- (void)exchangeValueAtIndex:(NSUInteger)idx1 + withValueAtIndex:(NSUInteger)idx2 { + if (idx1 >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)idx1, (unsigned long)_count]; + } + if (idx2 >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)idx2, (unsigned long)_count]; + } + double temp = _values[idx1]; + _values[idx1] = _values[idx2]; + _values[idx2] = temp; +} + +@end + +//%PDDM-EXPAND ARRAY_INTERFACE_SIMPLE(Bool, BOOL, %d) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool + +@implementation GPBBoolArray { + @package + BOOL *_values; + NSUInteger _count; + NSUInteger _capacity; +} + +@synthesize count = _count; + ++ (instancetype)array { + return [[[self alloc] initWithValues:NULL count:0] autorelease]; +} + ++ (instancetype)arrayWithValue:(BOOL)value { + // Cast is needed so the compiler knows what class we are invoking initWithValues: on to get + // the type correct. + return [[(GPBBoolArray*)[self alloc] initWithValues:&value count:1] autorelease]; +} + ++ (instancetype)arrayWithValueArray:(GPBBoolArray *)array { + return [[(GPBBoolArray*)[self alloc] initWithValueArray:array] autorelease]; +} + ++ (instancetype)arrayWithCapacity:(NSUInteger)count { + return [[[self alloc] initWithCapacity:count] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL count:0]; +} + +- (instancetype)initWithValueArray:(GPBBoolArray *)array { + return [self initWithValues:array->_values count:array->_count]; +} + +- (instancetype)initWithValues:(const BOOL [])values count:(NSUInteger)count { + self = [super init]; + if (self) { + if (count && values) { + _values = malloc(count * sizeof(BOOL)); + if (values != NULL) { + _capacity = count; + memcpy(_values, values, count * sizeof(BOOL)); + _count = count; + } else { + [self release]; + [NSException raise:NSMallocException + format:@"Failed to allocate %lu bytes", + (unsigned long)(count * sizeof(BOOL))]; + } + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)count { + self = [self initWithValues:NULL count:0]; + if (self && count) { + [self internalResizeToCapacity:count]; + } + return self; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBBoolArray allocWithZone:zone] initWithValues:_values count:_count]; +} + +- (void)dealloc { + NSAssert(!_autocreator, @"Autocreator must be cleared before release."); + free(_values); + [super dealloc]; +} + +- (BOOL)isEqual:(GPBBoolArray *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBBoolArray class]]) { + return NO; + } + return (_count == other->_count + && memcmp(_values, other->_values, (_count * sizeof(BOOL))) == 0); +} + +- (NSUInteger)hash { + // Follow NSArray's lead, and use the count as the hash. + return _count; +} + +- (NSString *)description { + NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> { ", [self class], self]; + for (NSUInteger i = 0, count = _count; i < count; ++i) { + if (i == 0) { + [result appendFormat:@"%d", _values[i]]; + } else { + [result appendFormat:@", %d", _values[i]]; + } + } + [result appendFormat:@" }"]; + return result; +} + +- (void)enumerateValuesWithBlock:(void (^)(BOOL value, NSUInteger idx, BOOL *stop))block { + [self enumerateValuesWithOptions:0 usingBlock:block]; +} + +- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts + usingBlock:(void (^)(BOOL value, NSUInteger idx, BOOL *stop))block { + // NSEnumerationConcurrent isn't currently supported (and Apple's docs say that is ok). + BOOL stop = NO; + if ((opts & NSEnumerationReverse) == 0) { + for (NSUInteger i = 0, count = _count; i < count; ++i) { + block(_values[i], i, &stop); + if (stop) break; + } + } else if (_count > 0) { + for (NSUInteger i = _count; i > 0; --i) { + block(_values[i - 1], (i - 1), &stop); + if (stop) break; + } + } +} + +- (BOOL)valueAtIndex:(NSUInteger)index { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + return _values[index]; +} + +- (void)internalResizeToCapacity:(NSUInteger)newCapacity { + _values = reallocf(_values, newCapacity * sizeof(BOOL)); + if (_values == NULL) { + _capacity = 0; + _count = 0; + [NSException raise:NSMallocException + format:@"Failed to allocate %lu bytes", + (unsigned long)(newCapacity * sizeof(BOOL))]; + } + _capacity = newCapacity; +} + +- (void)addValue:(BOOL)value { + [self addValues:&value count:1]; +} + +- (void)addValues:(const BOOL [])values count:(NSUInteger)count { + if (values == NULL || count == 0) return; + NSUInteger initialCount = _count; + NSUInteger newCount = initialCount + count; + if (newCount > _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } + _count = newCount;; + memcpy(&_values[initialCount], values, count * sizeof(BOOL)); + if (_autocreator) { + GPBAutocreatedArrayModified(_autocreator, self); + } +} + +- (void)insertValue:(BOOL)value atIndex:(NSUInteger)index { + if (index >= _count + 1) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count + 1]; + } + NSUInteger initialCount = _count; + NSUInteger newCount = initialCount + 1; + if (newCount > _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } + _count = newCount;; + if (index != initialCount) { + memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(BOOL)); + } + _values[index] = value; + if (_autocreator) { + GPBAutocreatedArrayModified(_autocreator, self); + } +} + +- (void)replaceValueAtIndex:(NSUInteger)index withValue:(BOOL)value { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + _values[index] = value; +} + +- (void)addValuesFromArray:(GPBBoolArray *)array { + [self addValues:array->_values count:array->_count]; +} + +- (void)removeValueAtIndex:(NSUInteger)index { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + NSUInteger newCount = _count - 1; + if (index != newCount) { + memmove(&_values[index], &_values[index + 1], (newCount - index) * sizeof(BOOL)); + } + _count = newCount; + if ((newCount + (2 * kChunkSize)) < _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } +} + +- (void)removeAll { + _count = 0; + if ((0 + (2 * kChunkSize)) < _capacity) { + [self internalResizeToCapacity:CapacityFromCount(0)]; + } +} + +- (void)exchangeValueAtIndex:(NSUInteger)idx1 + withValueAtIndex:(NSUInteger)idx2 { + if (idx1 >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)idx1, (unsigned long)_count]; + } + if (idx2 >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)idx2, (unsigned long)_count]; + } + BOOL temp = _values[idx1]; + _values[idx1] = _values[idx2]; + _values[idx2] = temp; +} + +@end + +//%PDDM-EXPAND-END (7 expansions) + +#pragma mark - Enum + +@implementation GPBEnumArray { + @package + GPBEnumValidationFunc _validationFunc; + int32_t *_values; + NSUInteger _count; + NSUInteger _capacity; +} + +@synthesize count = _count; +@synthesize validationFunc = _validationFunc; + ++ (instancetype)array { + return [[[self alloc] initWithValidationFunction:NULL + rawValues:NULL + count:0] autorelease]; +} + ++ (instancetype)arrayWithValidationFunction:(GPBEnumValidationFunc)func { + return [[[self alloc] initWithValidationFunction:func + rawValues:NULL + count:0] autorelease]; +} + ++ (instancetype)arrayWithValidationFunction:(GPBEnumValidationFunc)func + rawValue:(int32_t)value { + return [[[self alloc] initWithValidationFunction:func + rawValues:&value + count:1] autorelease]; +} + ++ (instancetype)arrayWithValueArray:(GPBEnumArray *)array { + return [[(GPBEnumArray*)[self alloc] initWithValueArray:array] autorelease]; +} + ++ (instancetype)arrayWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)count { + return [[[self alloc] initWithValidationFunction:func capacity:count] autorelease]; +} + +- (instancetype)init { + return [self initWithValidationFunction:NULL rawValues:NULL count:0]; +} + +- (instancetype)initWithValueArray:(GPBEnumArray *)array { + return [self initWithValidationFunction:array->_validationFunc + rawValues:array->_values + count:array->_count]; +} + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func { + return [self initWithValidationFunction:func rawValues:NULL count:0]; +} + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])values + count:(NSUInteger)count { + self = [super init]; + if (self) { + _validationFunc = (func != NULL ? func : ArrayDefault_IsValidValue); + if (count && values) { + _values = malloc(count * sizeof(int32_t)); + if (values != NULL) { + _capacity = count; + memcpy(_values, values, count * sizeof(int32_t)); + _count = count; + } else { + [self release]; + [NSException raise:NSMallocException + format:@"Failed to allocate %lu bytes", + (unsigned long)(count * sizeof(int32_t))]; + } + } + } + return self; +} + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)count { + self = [self initWithValidationFunction:func rawValues:NULL count:0]; + if (self && count) { + [self internalResizeToCapacity:count]; + } + return self; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBEnumArray allocWithZone:zone] + initWithValidationFunction:_validationFunc + rawValues:_values + count:_count]; +} + +//%PDDM-EXPAND ARRAY_IMMUTABLE_CORE(Enum, int32_t, Raw, %d) +// This block of code is generated, do not edit it directly. + +- (void)dealloc { + NSAssert(!_autocreator, @"Autocreator must be cleared before release."); + free(_values); + [super dealloc]; +} + +- (BOOL)isEqual:(GPBEnumArray *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBEnumArray class]]) { + return NO; + } + return (_count == other->_count + && memcmp(_values, other->_values, (_count * sizeof(int32_t))) == 0); +} + +- (NSUInteger)hash { + // Follow NSArray's lead, and use the count as the hash. + return _count; +} + +- (NSString *)description { + NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> { ", [self class], self]; + for (NSUInteger i = 0, count = _count; i < count; ++i) { + if (i == 0) { + [result appendFormat:@"%d", _values[i]]; + } else { + [result appendFormat:@", %d", _values[i]]; + } + } + [result appendFormat:@" }"]; + return result; +} + +- (void)enumerateRawValuesWithBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block { + [self enumerateRawValuesWithOptions:0 usingBlock:block]; +} + +- (void)enumerateRawValuesWithOptions:(NSEnumerationOptions)opts + usingBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block { + // NSEnumerationConcurrent isn't currently supported (and Apple's docs say that is ok). + BOOL stop = NO; + if ((opts & NSEnumerationReverse) == 0) { + for (NSUInteger i = 0, count = _count; i < count; ++i) { + block(_values[i], i, &stop); + if (stop) break; + } + } else if (_count > 0) { + for (NSUInteger i = _count; i > 0; --i) { + block(_values[i - 1], (i - 1), &stop); + if (stop) break; + } + } +} +//%PDDM-EXPAND-END ARRAY_IMMUTABLE_CORE(Enum, int32_t, Raw, %d) + +- (int32_t)valueAtIndex:(NSUInteger)index { +//%PDDM-EXPAND VALIDATE_RANGE(index, _count) +// This block of code is generated, do not edit it directly. + + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } +//%PDDM-EXPAND-END VALIDATE_RANGE(index, _count) + int32_t result = _values[index]; + if (!_validationFunc(result)) { + result = kGPBUnrecognizedEnumeratorValue; + } + return result; +} + +- (int32_t)rawValueAtIndex:(NSUInteger)index { +//%PDDM-EXPAND VALIDATE_RANGE(index, _count) +// This block of code is generated, do not edit it directly. + + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } +//%PDDM-EXPAND-END VALIDATE_RANGE(index, _count) + return _values[index]; +} + +- (void)enumerateValuesWithBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block { + [self enumerateValuesWithOptions:0 usingBlock:block]; +} + +- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts + usingBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block { + // NSEnumerationConcurrent isn't currently supported (and Apple's docs say that is ok). + BOOL stop = NO; + GPBEnumValidationFunc func = _validationFunc; + if ((opts & NSEnumerationReverse) == 0) { + int32_t *scan = _values; + int32_t *end = scan + _count; + for (NSUInteger i = 0; scan < end; ++i, ++scan) { + int32_t value = *scan; + if (!func(value)) { + value = kGPBUnrecognizedEnumeratorValue; + } + block(value, i, &stop); + if (stop) break; + } + } else if (_count > 0) { + int32_t *end = _values; + int32_t *scan = end + (_count - 1); + for (NSUInteger i = (_count - 1); scan >= end; --i, --scan) { + int32_t value = *scan; + if (!func(value)) { + value = kGPBUnrecognizedEnumeratorValue; + } + block(value, i, &stop); + if (stop) break; + } + } +} + +//%PDDM-EXPAND ARRAY_MUTABLE_CORE(Enum, int32_t, Raw, %d) +// This block of code is generated, do not edit it directly. + +- (void)internalResizeToCapacity:(NSUInteger)newCapacity { + _values = reallocf(_values, newCapacity * sizeof(int32_t)); + if (_values == NULL) { + _capacity = 0; + _count = 0; + [NSException raise:NSMallocException + format:@"Failed to allocate %lu bytes", + (unsigned long)(newCapacity * sizeof(int32_t))]; + } + _capacity = newCapacity; +} + +- (void)addRawValue:(int32_t)value { + [self addRawValues:&value count:1]; +} + +- (void)addRawValues:(const int32_t [])values count:(NSUInteger)count { + if (values == NULL || count == 0) return; + NSUInteger initialCount = _count; + NSUInteger newCount = initialCount + count; + if (newCount > _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } + _count = newCount;; + memcpy(&_values[initialCount], values, count * sizeof(int32_t)); + if (_autocreator) { + GPBAutocreatedArrayModified(_autocreator, self); + } +} + +- (void)insertRawValue:(int32_t)value atIndex:(NSUInteger)index { + if (index >= _count + 1) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count + 1]; + } + NSUInteger initialCount = _count; + NSUInteger newCount = initialCount + 1; + if (newCount > _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } + _count = newCount;; + if (index != initialCount) { + memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(int32_t)); + } + _values[index] = value; + if (_autocreator) { + GPBAutocreatedArrayModified(_autocreator, self); + } +} + +- (void)replaceValueAtIndex:(NSUInteger)index withRawValue:(int32_t)value { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + _values[index] = value; +} + +- (void)addRawValuesFromArray:(GPBEnumArray *)array { + [self addRawValues:array->_values count:array->_count]; +} + +- (void)removeValueAtIndex:(NSUInteger)index { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + NSUInteger newCount = _count - 1; + if (index != newCount) { + memmove(&_values[index], &_values[index + 1], (newCount - index) * sizeof(int32_t)); + } + _count = newCount; + if ((newCount + (2 * kChunkSize)) < _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } +} + +- (void)removeAll { + _count = 0; + if ((0 + (2 * kChunkSize)) < _capacity) { + [self internalResizeToCapacity:CapacityFromCount(0)]; + } +} + +- (void)exchangeValueAtIndex:(NSUInteger)idx1 + withValueAtIndex:(NSUInteger)idx2 { + if (idx1 >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)idx1, (unsigned long)_count]; + } + if (idx2 >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)idx2, (unsigned long)_count]; + } + int32_t temp = _values[idx1]; + _values[idx1] = _values[idx2]; + _values[idx2] = temp; +} + +//%PDDM-EXPAND MUTATION_METHODS(Enum, int32_t, , EnumValidationList, EnumValidationOne) +// This block of code is generated, do not edit it directly. + +- (void)addValue:(int32_t)value { + [self addValues:&value count:1]; +} + +- (void)addValues:(const int32_t [])values count:(NSUInteger)count { + if (values == NULL || count == 0) return; + GPBEnumValidationFunc func = _validationFunc; + for (NSUInteger i = 0; i < count; ++i) { + if (!func(values[i])) { + [NSException raise:NSInvalidArgumentException + format:@"%@: Attempt to set an unknown enum value (%d)", + [self class], values[i]]; + } + } + NSUInteger initialCount = _count; + NSUInteger newCount = initialCount + count; + if (newCount > _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } + _count = newCount;; + memcpy(&_values[initialCount], values, count * sizeof(int32_t)); + if (_autocreator) { + GPBAutocreatedArrayModified(_autocreator, self); + } +} + +- (void)insertValue:(int32_t)value atIndex:(NSUInteger)index { + if (index >= _count + 1) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count + 1]; + } + if (!_validationFunc(value)) { + [NSException raise:NSInvalidArgumentException + format:@"%@: Attempt to set an unknown enum value (%d)", + [self class], value]; + } + NSUInteger initialCount = _count; + NSUInteger newCount = initialCount + 1; + if (newCount > _capacity) { + [self internalResizeToCapacity:CapacityFromCount(newCount)]; + } + _count = newCount;; + if (index != initialCount) { + memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(int32_t)); + } + _values[index] = value; + if (_autocreator) { + GPBAutocreatedArrayModified(_autocreator, self); + } +} + +- (void)replaceValueAtIndex:(NSUInteger)index withValue:(int32_t)value { + if (index >= _count) { + [NSException raise:NSRangeException + format:@"Index (%lu) beyond bounds (%lu)", + (unsigned long)index, (unsigned long)_count]; + } + if (!_validationFunc(value)) { + [NSException raise:NSInvalidArgumentException + format:@"%@: Attempt to set an unknown enum value (%d)", + [self class], value]; + } + _values[index] = value; +} +//%PDDM-EXPAND-END (2 expansions) + +//%PDDM-DEFINE MUTATION_HOOK_EnumValidationList() +//% GPBEnumValidationFunc func = _validationFunc; +//% for (NSUInteger i = 0; i < count; ++i) { +//% if (!func(values[i])) { +//% [NSException raise:NSInvalidArgumentException +//% format:@"%@: Attempt to set an unknown enum value (%d)", +//% [self class], values[i]]; +//% } +//% } +//% +//%PDDM-DEFINE MUTATION_HOOK_EnumValidationOne() +//% if (!_validationFunc(value)) { +//% [NSException raise:NSInvalidArgumentException +//% format:@"%@: Attempt to set an unknown enum value (%d)", +//% [self class], value]; +//% } +//% + +@end + +#pragma mark - NSArray Subclass + +@implementation GPBAutocreatedArray { + NSMutableArray *_array; +} + +- (void)dealloc { + NSAssert(!_autocreator, @"Autocreator must be cleared before release."); + [_array release]; + [super dealloc]; +} + +#pragma mark Required NSArray overrides + +- (NSUInteger)count { + return [_array count]; +} + +- (id)objectAtIndex:(NSUInteger)idx { + return [_array objectAtIndex:idx]; +} + +#pragma mark Required NSMutableArray overrides + +// Only need to call GPBAutocreatedArrayModified() when adding things since +// we only autocreate empty arrays. + +- (void)insertObject:(id)anObject atIndex:(NSUInteger)idx { + if (_array == nil) { + _array = [[NSMutableArray alloc] init]; + } + [_array insertObject:anObject atIndex:idx]; + + if (_autocreator) { + GPBAutocreatedArrayModified(_autocreator, self); + } +} + +- (void)removeObject:(id)anObject { + [_array removeObject:anObject]; +} + +- (void)removeObjectAtIndex:(NSUInteger)idx { + [_array removeObjectAtIndex:idx]; +} + +- (void)addObject:(id)anObject { + if (_array == nil) { + _array = [[NSMutableArray alloc] init]; + } + [_array addObject:anObject]; + + if (_autocreator) { + GPBAutocreatedArrayModified(_autocreator, self); + } +} + +- (void)removeLastObject { + [_array removeLastObject]; +} + +- (void)replaceObjectAtIndex:(NSUInteger)idx withObject:(id)anObject { + [_array replaceObjectAtIndex:idx withObject:anObject]; +} + +#pragma mark Extra things hooked + +- (id)copyWithZone:(NSZone *)zone { + if (_array == nil) { + _array = [[NSMutableArray alloc] init]; + } + return [_array copyWithZone:zone]; +} + +- (id)mutableCopyWithZone:(NSZone *)zone { + if (_array == nil) { + _array = [[NSMutableArray alloc] init]; + } + return [_array mutableCopyWithZone:zone]; +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(id __unsafe_unretained [])buffer + count:(NSUInteger)len { + return [_array countByEnumeratingWithState:state objects:buffer count:len]; +} + +- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block { + [_array enumerateObjectsUsingBlock:block]; +} + +- (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts + usingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block { + [_array enumerateObjectsWithOptions:opts usingBlock:block]; +} + +@end diff --git a/objectivec/GPBArray_PackagePrivate.h b/objectivec/GPBArray_PackagePrivate.h new file mode 100644 index 00000000..35a45381 --- /dev/null +++ b/objectivec/GPBArray_PackagePrivate.h @@ -0,0 +1,130 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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. + +#import "GPBArray.h" + +@class GPBMessage; + +//%PDDM-DEFINE DECLARE_ARRAY_EXTRAS() +//%ARRAY_INTERFACE_EXTRAS(Int32, int32_t) +//%ARRAY_INTERFACE_EXTRAS(UInt32, uint32_t) +//%ARRAY_INTERFACE_EXTRAS(Int64, int64_t) +//%ARRAY_INTERFACE_EXTRAS(UInt64, uint64_t) +//%ARRAY_INTERFACE_EXTRAS(Float, float) +//%ARRAY_INTERFACE_EXTRAS(Double, double) +//%ARRAY_INTERFACE_EXTRAS(Bool, BOOL) +//%ARRAY_INTERFACE_EXTRAS(Enum, int32_t) + +//%PDDM-DEFINE ARRAY_INTERFACE_EXTRAS(NAME, TYPE) +//%#pragma mark - NAME +//% +//%@interface GPB##NAME##Array () { +//% @package +//% GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator; +//%} +//%@end +//% + +//%PDDM-EXPAND DECLARE_ARRAY_EXTRAS() +// This block of code is generated, do not edit it directly. + +#pragma mark - Int32 + +@interface GPBInt32Array () { + @package + GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator; +} +@end + +#pragma mark - UInt32 + +@interface GPBUInt32Array () { + @package + GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator; +} +@end + +#pragma mark - Int64 + +@interface GPBInt64Array () { + @package + GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator; +} +@end + +#pragma mark - UInt64 + +@interface GPBUInt64Array () { + @package + GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator; +} +@end + +#pragma mark - Float + +@interface GPBFloatArray () { + @package + GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator; +} +@end + +#pragma mark - Double + +@interface GPBDoubleArray () { + @package + GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator; +} +@end + +#pragma mark - Bool + +@interface GPBBoolArray () { + @package + GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator; +} +@end + +#pragma mark - Enum + +@interface GPBEnumArray () { + @package + GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator; +} +@end + +//%PDDM-EXPAND-END DECLARE_ARRAY_EXTRAS() + +#pragma mark - NSArray Subclass + +@interface GPBAutocreatedArray : NSMutableArray { + @package + GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator; +} +@end diff --git a/objectivec/GPBBootstrap.h b/objectivec/GPBBootstrap.h new file mode 100644 index 00000000..530eb5cb --- /dev/null +++ b/objectivec/GPBBootstrap.h @@ -0,0 +1,84 @@ +// 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. + +// The Objective C runtime has complete enough info that most protos don’t end +// up using this, so leaving it on is no cost or very little cost. If you +// happen to see it causing bloat, this is the way to disable it. If you do +// need to disable it, try only disabling it for Release builds as having +// full TextFormat can be useful for debugging. +#ifndef GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS +#define GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS 0 +#endif + +// Most uses of protocol buffers don't need field options, by default the +// static data will be compiled out, define this to 1 to include it. The only +// time you need this is if you are doing introspection of the protocol buffers. +#ifndef GPBOBJC_INCLUDE_FIELD_OPTIONS +#define GPBOBJC_INCLUDE_FIELD_OPTIONS 0 +#endif + +// Used in the generated code to give sizes to enums. int32_t was chosen based +// on the fact that Protocol Buffers enums are limited to this range. +// The complexity and double definition here are so we get the nice name +// for objective C, but also define the name with a trailing underscore so +// the Swift bridge will have one where the names line up to support short +// names since they are scoped to the enum. +// https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html#//apple_ref/doc/uid/TP40014216-CH8-XID_11 +#define GPB_ENUM(X) enum X##_ : int32_t X; typedef NS_ENUM(int32_t, X##_) +// GPB_ENUM_FWD_DECLARE is used for forward declaring enums ex: +// GPB_ENUM_FWD_DECLARE(Foo_Enum) +// @property (nonatomic) Foo_Enum value; +#define GPB_ENUM_FWD_DECLARE(_name) enum _name : int32_t + +// Based upon CF_INLINE. Forces inlining in release. +#if !defined(DEBUG) +#define GPB_INLINE static __inline__ __attribute__((always_inline)) +#else +#define GPB_INLINE static __inline__ +#endif + +// For use in public headers that might need to deal with ARC. +#ifndef GPB_UNSAFE_UNRETAINED +#if __has_feature(objc_arc) +#define GPB_UNSAFE_UNRETAINED __unsafe_unretained +#else +#define GPB_UNSAFE_UNRETAINED +#endif +#endif + +// If property name starts with init we need to annotate it to get past ARC. +// http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227 +#define GPB_METHOD_FAMILY_NONE __attribute__((objc_method_family(none))) + +// The protoc-gen-objc version which works with the current version of the +// generated Objective C sources. In general we don't want to change the +// runtime interfaces (or this version) as it means everything has to be +// regenerated. +#define GOOGLE_PROTOBUF_OBJC_GEN_VERSION 30000 diff --git a/objectivec/GPBCodedInputStream.h b/objectivec/GPBCodedInputStream.h new file mode 100644 index 00000000..db39c268 --- /dev/null +++ b/objectivec/GPBCodedInputStream.h @@ -0,0 +1,81 @@ +// 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. + +#import <Foundation/Foundation.h> + +@class GPBMessage; +@class GPBExtensionRegistry; + +// Reads and decodes protocol message fields. +// Subclassing of GPBCodedInputStream is NOT supported. +@interface GPBCodedInputStream : NSObject + ++ (instancetype)streamWithData:(NSData *)data; +- (instancetype)initWithData:(NSData *)data; + +// Attempt to read a field tag, returning zero if we have reached EOF. +// Protocol message parsers use this to read tags, since a protocol message +// may legally end wherever a tag occurs, and zero is not a valid tag number. +- (int32_t)readTag; + +- (double)readDouble; +- (float)readFloat; +- (uint64_t)readUInt64; +- (uint32_t)readUInt32; +- (int64_t)readInt64; +- (int32_t)readInt32; +- (uint64_t)readFixed64; +- (uint32_t)readFixed32; +- (int32_t)readEnum; +- (int32_t)readSFixed32; +- (int64_t)readSFixed64; +- (int32_t)readSInt32; +- (int64_t)readSInt64; +- (BOOL)readBool; +- (NSString *)readString; +- (NSData *)readData; + +// Read an embedded message field value from the stream. +- (void)readMessage:(GPBMessage *)message + extensionRegistry:(GPBExtensionRegistry *)extensionRegistry; + +// Reads and discards a single field, given its tag value. +- (BOOL)skipField:(int32_t)tag; + +// Reads and discards an entire message. This will read either until EOF +// or until an endgroup tag, whichever comes first. +- (void)skipMessage; + +// Verifies that the last call to readTag() returned the given tag value. +// This is used to verify that a nested group ended with the correct +// end tag. +- (void)checkLastTagWas:(int32_t)value; + +@end diff --git a/objectivec/GPBCodedInputStream.m b/objectivec/GPBCodedInputStream.m new file mode 100644 index 00000000..79d31fc7 --- /dev/null +++ b/objectivec/GPBCodedInputStream.m @@ -0,0 +1,801 @@ +// 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. + +#import "GPBCodedInputStream_PackagePrivate.h" + +#import "GPBDictionary_PackagePrivate.h" +#import "GPBMessage_PackagePrivate.h" +#import "GPBUnknownFieldSet_PackagePrivate.h" +#import "GPBUtilities_PackagePrivate.h" +#import "GPBWireFormat.h" + +static const NSUInteger kDefaultRecursionLimit = 64; + +static inline void CheckSize(GPBCodedInputStreamState *state, size_t size) { + size_t newSize = state->bufferPos + size; + if (newSize > state->bufferSize) { + [NSException raise:NSParseErrorException format:@""]; + } + if (newSize > state->currentLimit) { + // Fast forward to end of currentLimit; + state->bufferPos = state->currentLimit; + [NSException raise:NSParseErrorException format:@""]; + } +} + +static inline int8_t ReadRawByte(GPBCodedInputStreamState *state) { + CheckSize(state, sizeof(int8_t)); + return ((int8_t *)state->bytes)[state->bufferPos++]; +} + +static inline int32_t ReadRawLittleEndian32(GPBCodedInputStreamState *state) { + CheckSize(state, sizeof(int32_t)); + int32_t value = OSReadLittleInt32(state->bytes, state->bufferPos); + state->bufferPos += sizeof(int32_t); + return value; +} + +static inline int64_t ReadRawLittleEndian64(GPBCodedInputStreamState *state) { + CheckSize(state, sizeof(int64_t)); + int64_t value = OSReadLittleInt64(state->bytes, state->bufferPos); + state->bufferPos += sizeof(int64_t); + return value; +} + +static inline int32_t ReadRawVarint32(GPBCodedInputStreamState *state) { + int8_t tmp = ReadRawByte(state); + if (tmp >= 0) { + return tmp; + } + int32_t result = tmp & 0x7f; + if ((tmp = ReadRawByte(state)) >= 0) { + result |= tmp << 7; + } else { + result |= (tmp & 0x7f) << 7; + if ((tmp = ReadRawByte(state)) >= 0) { + result |= tmp << 14; + } else { + result |= (tmp & 0x7f) << 14; + if ((tmp = ReadRawByte(state)) >= 0) { + result |= tmp << 21; + } else { + result |= (tmp & 0x7f) << 21; + result |= (tmp = ReadRawByte(state)) << 28; + if (tmp < 0) { + // Discard upper 32 bits. + for (int i = 0; i < 5; i++) { + if (ReadRawByte(state) >= 0) { + return result; + } + } + [NSException raise:NSParseErrorException + format:@"Unable to read varint32"]; + } + } + } + } + return result; +} + +static inline int64_t ReadRawVarint64(GPBCodedInputStreamState *state) { + int32_t shift = 0; + int64_t result = 0; + while (shift < 64) { + int8_t b = ReadRawByte(state); + result |= (int64_t)(b & 0x7F) << shift; + if ((b & 0x80) == 0) { + return result; + } + shift += 7; + } + [NSException raise:NSParseErrorException format:@"Unable to read varint64"]; + return 0; +} + +static inline void SkipRawData(GPBCodedInputStreamState *state, size_t size) { + CheckSize(state, size); + state->bufferPos += size; +} + +double GPBCodedInputStreamReadDouble(GPBCodedInputStreamState *state) { + int64_t value = ReadRawLittleEndian64(state); + return GPBConvertInt64ToDouble(value); +} + +float GPBCodedInputStreamReadFloat(GPBCodedInputStreamState *state) { + int32_t value = ReadRawLittleEndian32(state); + return GPBConvertInt32ToFloat(value); +} + +uint64_t GPBCodedInputStreamReadUInt64(GPBCodedInputStreamState *state) { + uint64_t value = ReadRawVarint64(state); + return value; +} + +uint32_t GPBCodedInputStreamReadUInt32(GPBCodedInputStreamState *state) { + uint32_t value = ReadRawVarint32(state); + return value; +} + +int64_t GPBCodedInputStreamReadInt64(GPBCodedInputStreamState *state) { + int64_t value = ReadRawVarint64(state); + return value; +} + +int32_t GPBCodedInputStreamReadInt32(GPBCodedInputStreamState *state) { + int32_t value = ReadRawVarint32(state); + return value; +} + +uint64_t GPBCodedInputStreamReadFixed64(GPBCodedInputStreamState *state) { + uint64_t value = ReadRawLittleEndian64(state); + return value; +} + +uint32_t GPBCodedInputStreamReadFixed32(GPBCodedInputStreamState *state) { + uint32_t value = ReadRawLittleEndian32(state); + return value; +} + +int32_t GPBCodedInputStreamReadEnum(GPBCodedInputStreamState *state) { + int32_t value = ReadRawVarint32(state); + return value; +} + +int32_t GPBCodedInputStreamReadSFixed32(GPBCodedInputStreamState *state) { + int32_t value = ReadRawLittleEndian32(state); + return value; +} + +int64_t GPBCodedInputStreamReadSFixed64(GPBCodedInputStreamState *state) { + int64_t value = ReadRawLittleEndian64(state); + return value; +} + +int32_t GPBCodedInputStreamReadSInt32(GPBCodedInputStreamState *state) { + int32_t value = GPBDecodeZigZag32(ReadRawVarint32(state)); + return value; +} + +int64_t GPBCodedInputStreamReadSInt64(GPBCodedInputStreamState *state) { + int64_t value = GPBDecodeZigZag64(ReadRawVarint64(state)); + return value; +} + +BOOL GPBCodedInputStreamReadBool(GPBCodedInputStreamState *state) { + return ReadRawVarint32(state) != 0; +} + +int32_t GPBCodedInputStreamReadTag(GPBCodedInputStreamState *state) { + if (GPBCodedInputStreamIsAtEnd(state)) { + state->lastTag = 0; + return 0; + } + + state->lastTag = ReadRawVarint32(state); + if (state->lastTag == 0) { + // If we actually read zero, that's not a valid tag. + [NSException raise:NSParseErrorException + format:@"Invalid last tag %d", state->lastTag]; + } + return state->lastTag; +} + +NSString *GPBCodedInputStreamReadRetainedString( + GPBCodedInputStreamState *state) { + int32_t size = ReadRawVarint32(state); + NSString *result; + if (size == 0) { + result = @""; + } else { + CheckSize(state, size); + result = GPBCreateGPBStringWithUTF8(&state->bytes[state->bufferPos], size); + state->bufferPos += size; + } + return result; +} + +NSData *GPBCodedInputStreamReadRetainedData(GPBCodedInputStreamState *state) { + int32_t size = ReadRawVarint32(state); + if (size < 0) return nil; + CheckSize(state, size); + NSData *result = [[NSData alloc] initWithBytes:state->bytes + state->bufferPos + length:size]; + state->bufferPos += size; + return result; +} + +NSData *GPBCodedInputStreamReadRetainedDataNoCopy( + GPBCodedInputStreamState *state) { + int32_t size = ReadRawVarint32(state); + if (size < 0) return nil; + CheckSize(state, size); + // Cast is safe because freeWhenDone is NO. + NSData *result = [[NSData alloc] + initWithBytesNoCopy:(void *)(state->bytes + state->bufferPos) + length:size + freeWhenDone:NO]; + state->bufferPos += size; + return result; +} + +size_t GPBCodedInputStreamPushLimit(GPBCodedInputStreamState *state, + size_t byteLimit) { + byteLimit += state->bufferPos; + size_t oldLimit = state->currentLimit; + if (byteLimit > oldLimit) { + [NSException raise:NSInvalidArgumentException + format:@"byteLimit > oldLimit: %tu > %tu", byteLimit, oldLimit]; + } + state->currentLimit = byteLimit; + return oldLimit; +} + +void GPBCodedInputStreamPopLimit(GPBCodedInputStreamState *state, + size_t oldLimit) { + state->currentLimit = oldLimit; +} + +size_t GPBCodedInputStreamBytesUntilLimit(GPBCodedInputStreamState *state) { + if (state->currentLimit == SIZE_T_MAX) { + return state->currentLimit; + } + + return state->currentLimit - state->bufferPos; +} + +BOOL GPBCodedInputStreamIsAtEnd(GPBCodedInputStreamState *state) { + return (state->bufferPos == state->bufferSize) || + (state->bufferPos == state->currentLimit); +} + +void GPBCodedInputStreamCheckLastTagWas(GPBCodedInputStreamState *state, + int32_t value) { + if (state->lastTag != value) { + [NSException raise:NSParseErrorException + format:@"Last tag: %d should be %d", state->lastTag, value]; + } +} + +@implementation GPBCodedInputStream + ++ (instancetype)streamWithData:(NSData *)data { + return [[[self alloc] initWithData:data] autorelease]; +} + +- (instancetype)initWithData:(NSData *)data { + if ((self = [super init])) { +#ifdef DEBUG + NSCAssert([self class] == [GPBCodedInputStream class], + @"Subclassing of GPBCodedInputStream is not allowed."); +#endif + buffer_ = [data retain]; + state_.bytes = (const uint8_t *)[data bytes]; + state_.bufferSize = [data length]; + state_.currentLimit = NSUIntegerMax; + } + return self; +} + +- (void)dealloc { + [buffer_ release]; + [super dealloc]; +} + +- (int32_t)readTag { + return GPBCodedInputStreamReadTag(&state_); +} + +- (void)checkLastTagWas:(int32_t)value { + GPBCodedInputStreamCheckLastTagWas(&state_, value); +} + +- (BOOL)skipField:(int32_t)tag { + switch (GPBWireFormatGetTagWireType(tag)) { + case GPBWireFormatVarint: + GPBCodedInputStreamReadInt32(&state_); + return YES; + case GPBWireFormatFixed64: + SkipRawData(&state_, sizeof(int64_t)); + return YES; + case GPBWireFormatLengthDelimited: + SkipRawData(&state_, ReadRawVarint32(&state_)); + return YES; + case GPBWireFormatStartGroup: + [self skipMessage]; + GPBCodedInputStreamCheckLastTagWas( + &state_, GPBWireFormatMakeTag(GPBWireFormatGetTagFieldNumber(tag), + GPBWireFormatEndGroup)); + return YES; + case GPBWireFormatEndGroup: + return NO; + case GPBWireFormatFixed32: + SkipRawData(&state_, sizeof(int32_t)); + return YES; + } + [NSException raise:NSParseErrorException format:@"Invalid tag %d", tag]; + return NO; +} + +- (void)skipMessage { + while (YES) { + int32_t tag = GPBCodedInputStreamReadTag(&state_); + if (tag == 0 || ![self skipField:tag]) { + return; + } + } +} + +- (double)readDouble { + return GPBCodedInputStreamReadDouble(&state_); +} + +- (float)readFloat { + return GPBCodedInputStreamReadFloat(&state_); +} + +- (uint64_t)readUInt64 { + return GPBCodedInputStreamReadUInt64(&state_); +} + +- (int64_t)readInt64 { + return GPBCodedInputStreamReadInt64(&state_); +} + +- (int32_t)readInt32 { + return GPBCodedInputStreamReadInt32(&state_); +} + +- (uint64_t)readFixed64 { + return GPBCodedInputStreamReadFixed64(&state_); +} + +- (uint32_t)readFixed32 { + return GPBCodedInputStreamReadFixed32(&state_); +} + +- (BOOL)readBool { + return GPBCodedInputStreamReadBool(&state_); +} + +- (NSString *)readString { + return [GPBCodedInputStreamReadRetainedString(&state_) autorelease]; +} + +- (void)readGroup:(int32_t)fieldNumber + message:(GPBMessage *)message + extensionRegistry:(GPBExtensionRegistry *)extensionRegistry { + if (state_.recursionDepth >= kDefaultRecursionLimit) { + [NSException raise:NSParseErrorException + format:@"recursionDepth(%tu) >= %tu", state_.recursionDepth, + kDefaultRecursionLimit]; + } + ++state_.recursionDepth; + [message mergeFromCodedInputStream:self extensionRegistry:extensionRegistry]; + GPBCodedInputStreamCheckLastTagWas( + &state_, GPBWireFormatMakeTag(fieldNumber, GPBWireFormatEndGroup)); + --state_.recursionDepth; +} + +- (void)readUnknownGroup:(int32_t)fieldNumber + message:(GPBUnknownFieldSet *)message { + if (state_.recursionDepth >= kDefaultRecursionLimit) { + [NSException raise:NSParseErrorException + format:@"recursionDepth(%tu) >= %tu", state_.recursionDepth, + kDefaultRecursionLimit]; + } + ++state_.recursionDepth; + [message mergeFromCodedInputStream:self]; + GPBCodedInputStreamCheckLastTagWas( + &state_, GPBWireFormatMakeTag(fieldNumber, GPBWireFormatEndGroup)); + --state_.recursionDepth; +} + +- (void)readMessage:(GPBMessage *)message + extensionRegistry:(GPBExtensionRegistry *)extensionRegistry { + int32_t length = ReadRawVarint32(&state_); + if (state_.recursionDepth >= kDefaultRecursionLimit) { + [NSException raise:NSParseErrorException + format:@"recursionDepth(%tu) >= %tu", state_.recursionDepth, + kDefaultRecursionLimit]; + } + size_t oldLimit = GPBCodedInputStreamPushLimit(&state_, length); + ++state_.recursionDepth; + [message mergeFromCodedInputStream:self extensionRegistry:extensionRegistry]; + GPBCodedInputStreamCheckLastTagWas(&state_, 0); + --state_.recursionDepth; + GPBCodedInputStreamPopLimit(&state_, oldLimit); +} + +- (void)readMapEntry:(id)mapDictionary + extensionRegistry:(GPBExtensionRegistry *)extensionRegistry + field:(GPBFieldDescriptor *)field + parentMessage:(GPBMessage *)parentMessage { + int32_t length = ReadRawVarint32(&state_); + if (state_.recursionDepth >= kDefaultRecursionLimit) { + [NSException raise:NSParseErrorException + format:@"recursionDepth(%tu) >= %tu", state_.recursionDepth, + kDefaultRecursionLimit]; + } + size_t oldLimit = GPBCodedInputStreamPushLimit(&state_, length); + ++state_.recursionDepth; + GPBDictionaryReadEntry(mapDictionary, self, extensionRegistry, field, + parentMessage); + GPBCodedInputStreamCheckLastTagWas(&state_, 0); + --state_.recursionDepth; + GPBCodedInputStreamPopLimit(&state_, oldLimit); +} + +- (NSData *)readData { + return [GPBCodedInputStreamReadRetainedData(&state_) autorelease]; +} + +- (uint32_t)readUInt32 { + return GPBCodedInputStreamReadUInt32(&state_); +} + +- (int32_t)readEnum { + return GPBCodedInputStreamReadEnum(&state_); +} + +- (int32_t)readSFixed32 { + return GPBCodedInputStreamReadSFixed32(&state_); +} + +- (int64_t)readSFixed64 { + return GPBCodedInputStreamReadSFixed64(&state_); +} + +- (int32_t)readSInt32 { + return GPBCodedInputStreamReadSInt32(&state_); +} + +- (int64_t)readSInt64 { + return GPBCodedInputStreamReadSInt64(&state_); +} + +@end + +@implementation GPBString { + @package + CFStringRef string_; + unsigned char *utf8_; + NSUInteger utf8Len_; + + // This lock is used to gate access to utf8_. Once GPBStringInitStringValue() + // has been called, string_ will be filled in, and utf8_ will be NULL. + OSSpinLock lock_; + + BOOL hasBOM_; + BOOL is7BitAscii_; +} + +// Returns true if the passed in bytes are 7 bit ascii. +// This routine needs to be fast. +static inline bool AreBytesIn7BitASCII(const uint8_t *bytes, NSUInteger len) { +// In the loops below, it's more efficient to collect rather than do +// conditional at every step. +#if __LP64__ + // Align bytes. This is especially important in case of 3 byte BOM. + while (len > 0 && ((size_t)bytes & 0x07)) { + if (*bytes++ & 0x80) return false; + len--; + } + while (len >= 32) { + uint64_t val = *(const uint64_t *)bytes; + uint64_t hiBits = (val & 0x8080808080808080ULL); + bytes += 8; + val = *(const uint64_t *)bytes; + hiBits |= (val & 0x8080808080808080ULL); + bytes += 8; + val = *(const uint64_t *)bytes; + hiBits |= (val & 0x8080808080808080ULL); + bytes += 8; + val = *(const uint64_t *)bytes; + if (hiBits | (val & 0x8080808080808080ULL)) return false; + bytes += 8; + len -= 32; + } + + while (len >= 16) { + uint64_t val = *(const uint64_t *)bytes; + uint64_t hiBits = (val & 0x8080808080808080ULL); + bytes += 8; + val = *(const uint64_t *)bytes; + if (hiBits | (val & 0x8080808080808080ULL)) return false; + bytes += 8; + len -= 16; + } + + while (len >= 8) { + uint64_t val = *(const uint64_t *)bytes; + if (val & 0x8080808080808080ULL) return false; + bytes += 8; + len -= 8; + } +#else // __LP64__ + // Align bytes. This is especially important in case of 3 byte BOM. + while (len > 0 && ((size_t)bytes & 0x03)) { + if (*bytes++ & 0x80) return false; + len--; + } + while (len >= 16) { + uint32_t val = *(const uint32_t *)bytes; + uint32_t hiBits = (val & 0x80808080U); + bytes += 4; + val = *(const uint32_t *)bytes; + hiBits |= (val & 0x80808080U); + bytes += 4; + val = *(const uint32_t *)bytes; + hiBits |= (val & 0x80808080U); + bytes += 4; + val = *(const uint32_t *)bytes; + if (hiBits | (val & 0x80808080U)) return false; + bytes += 4; + len -= 16; + } + + while (len >= 8) { + uint32_t val = *(const uint32_t *)bytes; + uint32_t hiBits = (val & 0x80808080U); + bytes += 4; + val = *(const uint32_t *)bytes; + if (hiBits | (val & 0x80808080U)) return false; + bytes += 4; + len -= 8; + } +#endif // __LP64__ + + while (len >= 4) { + uint32_t val = *(const uint32_t *)bytes; + if (val & 0x80808080U) return false; + bytes += 4; + len -= 4; + } + + while (len--) { + if (*bytes++ & 0x80) return false; + } + + return true; +} + +static inline void GPBStringInitStringValue(GPBString *string) { + OSSpinLockLock(&string->lock_); + GPBStringInitStringValueAlreadyLocked(string); + OSSpinLockUnlock(&string->lock_); +} + +static void GPBStringInitStringValueAlreadyLocked(GPBString *string) { + if (string->string_ == NULL && string->utf8_ != NULL) { + // Using kCFAllocatorMalloc for contentsDeallocator, as buffer in + // string->utf8_ is being handed off. + string->string_ = CFStringCreateWithBytesNoCopy( + NULL, string->utf8_, string->utf8Len_, kCFStringEncodingUTF8, false, + kCFAllocatorMalloc); + if (!string->string_) { +#ifdef DEBUG + // https://developers.google.com/protocol-buffers/docs/proto#scalar + NSLog(@"UTF8 failure, is some field type 'string' when it should be " + @"'bytes'?"); +#endif + string->string_ = CFSTR(""); + string->utf8Len_ = 0; + // On failure, we have to clean up the buffer. + free(string->utf8_); + } + string->utf8_ = NULL; + } +} + +GPBString *GPBCreateGPBStringWithUTF8(const void *bytes, NSUInteger length) { + GPBString *result = [[GPBString alloc] initWithBytes:bytes length:length]; + return result; +} + +- (instancetype)initWithBytes:(const void *)bytes length:(NSUInteger)length { + self = [super init]; + if (self) { + utf8_ = malloc(length); + memcpy(utf8_, bytes, length); + utf8Len_ = length; + lock_ = OS_SPINLOCK_INIT; + is7BitAscii_ = AreBytesIn7BitASCII(bytes, length); + if (length >= 3 && memcmp(utf8_, "\xef\xbb\xbf", 3) == 0) { + // We can't just remove the BOM from the string here, because in the case + // where we have > 1 BOM at the beginning of the string, we will remove one, + // and the internal NSString we create will remove the next one, and we will + // end up with a GPBString != NSString issue. + // We also just can't remove all the BOMs because then we would end up with + // potential cases where a GPBString and an NSString made with the same + // UTF8 buffer would in fact be different. + // We record the fact we have a BOM, and use it as necessary to simulate + // what NSString would return for various calls. + hasBOM_ = YES; +#if DEBUG + // Sending BOMs across the line is just wasting bits. + NSLog(@"Bad data? String should not have BOM!"); +#endif // DEBUG + } + } + return self; +} + +- (void)dealloc { + if (string_ != NULL) { + CFRelease(string_); + } + if (utf8_ != NULL) { + free(utf8_); + } + [super dealloc]; +} + +// Required NSString overrides. +- (NSUInteger)length { + if (is7BitAscii_) { + return utf8Len_; + } else { + GPBStringInitStringValue(self); + return CFStringGetLength(string_); + } +} + +- (unichar)characterAtIndex:(NSUInteger)anIndex { + OSSpinLockLock(&lock_); + if (is7BitAscii_ && utf8_) { + unichar result = utf8_[anIndex]; + OSSpinLockUnlock(&lock_); + return result; + } else { + GPBStringInitStringValueAlreadyLocked(self); + OSSpinLockUnlock(&lock_); + return CFStringGetCharacterAtIndex(string_, anIndex); + } +} + +// Override a couple of methods that typically want high performance. + +- (id)copyWithZone:(NSZone *)zone { + GPBStringInitStringValue(self); + return [(NSString *)string_ copyWithZone:zone]; +} + +- (id)mutableCopyWithZone:(NSZone *)zone { + GPBStringInitStringValue(self); + return [(NSString *)string_ mutableCopyWithZone:zone]; +} + +- (NSUInteger)hash { + // Must convert to string here to make sure that the hash is always + // consistent no matter what state the GPBString is in. + GPBStringInitStringValue(self); + return CFHash(string_); +} + +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if ([object isKindOfClass:[NSString class]]) { + GPBStringInitStringValue(self); + return CFStringCompare(string_, (CFStringRef)object, 0) == + kCFCompareEqualTo; + } + return NO; +} + +- (void)getCharacters:(unichar *)buffer range:(NSRange)aRange { + OSSpinLockLock(&lock_); + if (is7BitAscii_ && utf8_) { + unsigned char *bytes = &(utf8_[aRange.location]); + for (NSUInteger i = 0; i < aRange.length; ++i) { + buffer[i] = bytes[i]; + } + OSSpinLockUnlock(&lock_); + } else { + GPBStringInitStringValueAlreadyLocked(self); + OSSpinLockUnlock(&lock_); + CFStringGetCharacters(string_, CFRangeMake(aRange.location, aRange.length), + buffer); + } +} + +- (NSUInteger)lengthOfBytesUsingEncoding:(NSStringEncoding)encoding { + if ((encoding == NSUTF8StringEncoding) || + (encoding == NSASCIIStringEncoding && is7BitAscii_)) { + return utf8Len_ - (hasBOM_ ? 3 : 0); + } else { + GPBStringInitStringValue(self); + return [(NSString *)string_ lengthOfBytesUsingEncoding:encoding]; + } +} + +- (BOOL)getBytes:(void *)buffer + maxLength:(NSUInteger)maxLength + usedLength:(NSUInteger *)usedLength + encoding:(NSStringEncoding)encoding + options:(NSStringEncodingConversionOptions)options + range:(NSRange)range + remainingRange:(NSRangePointer)remainingRange { + // [NSString getBytes:maxLength:usedLength:encoding:options:range:remainingRange] + // does not return reliable results if the maxLength argument is 0 + // (Radar 16385183). Therefore we have special cased it as a slow case so + // that it behaves however Apple intends it to behave. It should be a rare + // case. + // + // [NSString getBytes:maxLength:usedLength:encoding:options:range:remainingRange] + // does not return reliable results if the range is outside of the strings + // length (Radar 16396177). Therefore we have special cased it as a slow + // case so that it behaves however Apple intends it to behave. It should + // be a rare case. + // + // We can optimize the UTF8StringEncoding and NSASCIIStringEncoding with no + // options cases. + if ((options == 0) && + (encoding == NSUTF8StringEncoding || encoding == NSASCIIStringEncoding) && + (maxLength != 0) && + (NSMaxRange(range) <= utf8Len_)) { + // Might be able to optimize it. + OSSpinLockLock(&lock_); + if (is7BitAscii_ && utf8_) { + NSUInteger length = range.length; + length = (length < maxLength) ? length : maxLength; + memcpy(buffer, utf8_ + range.location, length); + if (usedLength) { + *usedLength = length; + } + if (remainingRange) { + remainingRange->location = range.location + length; + remainingRange->length = range.length - length; + } + OSSpinLockUnlock(&lock_); + if (length > 0) { + return YES; + } else { + return NO; + } + } else { + GPBStringInitStringValueAlreadyLocked(self); + OSSpinLockUnlock(&lock_); + } + } else { + GPBStringInitStringValue(self); + } + return [(NSString *)string_ getBytes:buffer + maxLength:maxLength + usedLength:usedLength + encoding:encoding + options:options + range:range + remainingRange:remainingRange]; +} + +@end diff --git a/objectivec/GPBCodedInputStream_PackagePrivate.h b/objectivec/GPBCodedInputStream_PackagePrivate.h new file mode 100644 index 00000000..ba6471ef --- /dev/null +++ b/objectivec/GPBCodedInputStream_PackagePrivate.h @@ -0,0 +1,131 @@ +// 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. + +// This header is private to the ProtobolBuffers library and must NOT be +// included by any sources outside this library. The contents of this file are +// subject to change at any time without notice. + +#import "GPBCodedInputStream.h" + +#import <libkern/OSAtomic.h> + +@class GPBUnknownFieldSet; +@class GPBFieldDescriptor; + +// GPBString is a string subclass that avoids the overhead of initializing +// a full NSString until it is actually needed. Lots of protocol buffers contain +// strings, and instantiating all of those strings and having them parsed to +// verify correctness when the message was being read was expensive, when many +// of the strings were never being used. +// +// Note for future-self. I tried implementing this using a NSProxy. +// Turned out the performance was horrible in client apps because folks +// like to use libraries like SBJSON that grab characters one at a time. +// The proxy overhead was a killer. +@interface GPBString : NSString +@end + +typedef struct GPBCodedInputStreamState { + const uint8_t *bytes; + size_t bufferSize; + size_t bufferPos; + + // For parsing subsections of an input stream you can put a hard limit on + // how much should be read. Normally the limit is the end of the stream, + // but you can adjust it to anywhere, and if you hit it you will be at the + // end of the stream, until you adjust the limit. + size_t currentLimit; + int32_t lastTag; + NSUInteger recursionDepth; +} GPBCodedInputStreamState; + +@interface GPBCodedInputStream () { + @package + struct GPBCodedInputStreamState state_; + NSData *buffer_; +} + +// Group support is deprecated, so we hide this interface from users, but +// support for older data. +- (void)readGroup:(int32_t)fieldNumber + message:(GPBMessage *)message + extensionRegistry:(GPBExtensionRegistry *)extensionRegistry; + +// Reads a group field value from the stream and merges it into the given +// UnknownFieldSet. +- (void)readUnknownGroup:(int32_t)fieldNumber + message:(GPBUnknownFieldSet *)message; + +// Reads a map entry. +- (void)readMapEntry:(id)mapDictionary + extensionRegistry:(GPBExtensionRegistry *)extensionRegistry + field:(GPBFieldDescriptor *)field + parentMessage:(GPBMessage *)parentMessage; +@end + +CF_EXTERN_C_BEGIN + +// Returns a GPBString with a +1 retain count. +GPBString *GPBCreateGPBStringWithUTF8(const void *bytes, NSUInteger length) + __attribute__((ns_returns_retained)); + +int32_t GPBCodedInputStreamReadTag(GPBCodedInputStreamState *state); + +double GPBCodedInputStreamReadDouble(GPBCodedInputStreamState *state); +float GPBCodedInputStreamReadFloat(GPBCodedInputStreamState *state); +uint64_t GPBCodedInputStreamReadUInt64(GPBCodedInputStreamState *state); +uint32_t GPBCodedInputStreamReadUInt32(GPBCodedInputStreamState *state); +int64_t GPBCodedInputStreamReadInt64(GPBCodedInputStreamState *state); +int32_t GPBCodedInputStreamReadInt32(GPBCodedInputStreamState *state); +uint64_t GPBCodedInputStreamReadFixed64(GPBCodedInputStreamState *state); +uint32_t GPBCodedInputStreamReadFixed32(GPBCodedInputStreamState *state); +int32_t GPBCodedInputStreamReadEnum(GPBCodedInputStreamState *state); +int32_t GPBCodedInputStreamReadSFixed32(GPBCodedInputStreamState *state); +int64_t GPBCodedInputStreamReadSFixed64(GPBCodedInputStreamState *state); +int32_t GPBCodedInputStreamReadSInt32(GPBCodedInputStreamState *state); +int64_t GPBCodedInputStreamReadSInt64(GPBCodedInputStreamState *state); +BOOL GPBCodedInputStreamReadBool(GPBCodedInputStreamState *state); +NSString *GPBCodedInputStreamReadRetainedString(GPBCodedInputStreamState *state) + __attribute((ns_returns_retained)); +NSData *GPBCodedInputStreamReadRetainedData(GPBCodedInputStreamState *state) + __attribute((ns_returns_retained)); +NSData *GPBCodedInputStreamReadRetainedDataNoCopy( + GPBCodedInputStreamState *state) __attribute((ns_returns_retained)); + +size_t GPBCodedInputStreamPushLimit(GPBCodedInputStreamState *state, + size_t byteLimit); +void GPBCodedInputStreamPopLimit(GPBCodedInputStreamState *state, + size_t oldLimit); +size_t GPBCodedInputStreamBytesUntilLimit(GPBCodedInputStreamState *state); +BOOL GPBCodedInputStreamIsAtEnd(GPBCodedInputStreamState *state); +void GPBCodedInputStreamCheckLastTagWas(GPBCodedInputStreamState *state, + int32_t value); + +CF_EXTERN_C_END diff --git a/objectivec/GPBCodedOutputStream.h b/objectivec/GPBCodedOutputStream.h new file mode 100644 index 00000000..1f1eb38a --- /dev/null +++ b/objectivec/GPBCodedOutputStream.h @@ -0,0 +1,340 @@ +// 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. + +#import <Foundation/Foundation.h> + +#import "GPBTypes.h" +#import "GPBWireFormat.h" + +@class GPBBoolArray; +@class GPBDoubleArray; +@class GPBEnumArray; +@class GPBFloatArray; +@class GPBMessage; +@class GPBInt32Array; +@class GPBInt64Array; +@class GPBUInt32Array; +@class GPBUInt64Array; +@class GPBUnknownFieldSet; + +@interface GPBCodedOutputStream : NSObject + +// Creates a new stream to write into data. Data must be sized to fit or it +// will error when it runs out of space. ++ (instancetype)streamWithData:(NSMutableData *)data; ++ (instancetype)streamWithOutputStream:(NSOutputStream *)output; ++ (instancetype)streamWithOutputStream:(NSOutputStream *)output + bufferSize:(size_t)bufferSize; + +- (instancetype)initWithOutputStream:(NSOutputStream *)output; +- (instancetype)initWithData:(NSMutableData *)data; +- (instancetype)initWithOutputStream:(NSOutputStream *)output + bufferSize:(size_t)bufferSize; +- (instancetype)initWithOutputStream:(NSOutputStream *)output + data:(NSMutableData *)data; + +- (void)flush; + +- (void)writeRawByte:(uint8_t)value; + +- (void)writeTag:(uint32_t)fieldNumber format:(GPBWireFormat)format; + +- (void)writeRawLittleEndian32:(int32_t)value; +- (void)writeRawLittleEndian64:(int64_t)value; + +- (void)writeRawVarint32:(int32_t)value; +- (void)writeRawVarint64:(int64_t)value; + +// Note that this will truncate 64 bit values to 32. +- (void)writeRawVarintSizeTAs32:(size_t)value; + +- (void)writeRawData:(NSData *)data; +- (void)writeRawPtr:(const void *)data + offset:(size_t)offset + length:(size_t)length; + +//%PDDM-EXPAND _WRITE_DECLS() +// This block of code is generated, do not edit it directly. + +- (void)writeDouble:(int32_t)fieldNumber value:(double)value; +- (void)writeDoubles:(int32_t)fieldNumber + values:(GPBDoubleArray *)values + tag:(uint32_t)tag; +- (void)writeDoubleNoTag:(double)value; + +- (void)writeFloat:(int32_t)fieldNumber value:(float)value; +- (void)writeFloats:(int32_t)fieldNumber + values:(GPBFloatArray *)values + tag:(uint32_t)tag; +- (void)writeFloatNoTag:(float)value; + +- (void)writeUInt64:(int32_t)fieldNumber value:(uint64_t)value; +- (void)writeUInt64s:(int32_t)fieldNumber + values:(GPBUInt64Array *)values + tag:(uint32_t)tag; +- (void)writeUInt64NoTag:(uint64_t)value; + +- (void)writeInt64:(int32_t)fieldNumber value:(int64_t)value; +- (void)writeInt64s:(int32_t)fieldNumber + values:(GPBInt64Array *)values + tag:(uint32_t)tag; +- (void)writeInt64NoTag:(int64_t)value; + +- (void)writeInt32:(int32_t)fieldNumber value:(int32_t)value; +- (void)writeInt32s:(int32_t)fieldNumber + values:(GPBInt32Array *)values + tag:(uint32_t)tag; +- (void)writeInt32NoTag:(int32_t)value; + +- (void)writeUInt32:(int32_t)fieldNumber value:(uint32_t)value; +- (void)writeUInt32s:(int32_t)fieldNumber + values:(GPBUInt32Array *)values + tag:(uint32_t)tag; +- (void)writeUInt32NoTag:(uint32_t)value; + +- (void)writeFixed64:(int32_t)fieldNumber value:(uint64_t)value; +- (void)writeFixed64s:(int32_t)fieldNumber + values:(GPBUInt64Array *)values + tag:(uint32_t)tag; +- (void)writeFixed64NoTag:(uint64_t)value; + +- (void)writeFixed32:(int32_t)fieldNumber value:(uint32_t)value; +- (void)writeFixed32s:(int32_t)fieldNumber + values:(GPBUInt32Array *)values + tag:(uint32_t)tag; +- (void)writeFixed32NoTag:(uint32_t)value; + +- (void)writeSInt32:(int32_t)fieldNumber value:(int32_t)value; +- (void)writeSInt32s:(int32_t)fieldNumber + values:(GPBInt32Array *)values + tag:(uint32_t)tag; +- (void)writeSInt32NoTag:(int32_t)value; + +- (void)writeSInt64:(int32_t)fieldNumber value:(int64_t)value; +- (void)writeSInt64s:(int32_t)fieldNumber + values:(GPBInt64Array *)values + tag:(uint32_t)tag; +- (void)writeSInt64NoTag:(int64_t)value; + +- (void)writeSFixed64:(int32_t)fieldNumber value:(int64_t)value; +- (void)writeSFixed64s:(int32_t)fieldNumber + values:(GPBInt64Array *)values + tag:(uint32_t)tag; +- (void)writeSFixed64NoTag:(int64_t)value; + +- (void)writeSFixed32:(int32_t)fieldNumber value:(int32_t)value; +- (void)writeSFixed32s:(int32_t)fieldNumber + values:(GPBInt32Array *)values + tag:(uint32_t)tag; +- (void)writeSFixed32NoTag:(int32_t)value; + +- (void)writeBool:(int32_t)fieldNumber value:(BOOL)value; +- (void)writeBools:(int32_t)fieldNumber + values:(GPBBoolArray *)values + tag:(uint32_t)tag; +- (void)writeBoolNoTag:(BOOL)value; + +- (void)writeEnum:(int32_t)fieldNumber value:(int32_t)value; +- (void)writeEnums:(int32_t)fieldNumber + values:(GPBEnumArray *)values + tag:(uint32_t)tag; +- (void)writeEnumNoTag:(int32_t)value; + +- (void)writeString:(int32_t)fieldNumber value:(NSString *)value; +- (void)writeStrings:(int32_t)fieldNumber values:(NSArray *)values; +- (void)writeStringNoTag:(NSString *)value; + +- (void)writeMessage:(int32_t)fieldNumber value:(GPBMessage *)value; +- (void)writeMessages:(int32_t)fieldNumber values:(NSArray *)values; +- (void)writeMessageNoTag:(GPBMessage *)value; + +- (void)writeData:(int32_t)fieldNumber value:(NSData *)value; +- (void)writeDatas:(int32_t)fieldNumber values:(NSArray *)values; +- (void)writeDataNoTag:(NSData *)value; + +- (void)writeGroup:(int32_t)fieldNumber + value:(GPBMessage *)value; +- (void)writeGroups:(int32_t)fieldNumber values:(NSArray *)values; +- (void)writeGroupNoTag:(int32_t)fieldNumber + value:(GPBMessage *)value; + +- (void)writeUnknownGroup:(int32_t)fieldNumber + value:(GPBUnknownFieldSet *)value; +- (void)writeUnknownGroups:(int32_t)fieldNumber values:(NSArray *)values; +- (void)writeUnknownGroupNoTag:(int32_t)fieldNumber + value:(GPBUnknownFieldSet *)value; + +//%PDDM-EXPAND-END _WRITE_DECLS() + +// Write a MessageSet extension field to the stream. For historical reasons, +// the wire format differs from normal fields. +- (void)writeMessageSetExtension:(int32_t)fieldNumber value:(GPBMessage *)value; + +// Write an unparsed MessageSet extension field to the stream. For +// historical reasons, the wire format differs from normal fields. +- (void)writeRawMessageSetExtension:(int32_t)fieldNumber value:(NSData *)value; + +@end + +CF_EXTERN_C_BEGIN + +size_t GPBComputeDoubleSize(int32_t fieldNumber, double value) + __attribute__((const)); +size_t GPBComputeFloatSize(int32_t fieldNumber, float value) + __attribute__((const)); +size_t GPBComputeUInt64Size(int32_t fieldNumber, uint64_t value) + __attribute__((const)); +size_t GPBComputeInt64Size(int32_t fieldNumber, int64_t value) + __attribute__((const)); +size_t GPBComputeInt32Size(int32_t fieldNumber, int32_t value) + __attribute__((const)); +size_t GPBComputeFixed64Size(int32_t fieldNumber, uint64_t value) + __attribute__((const)); +size_t GPBComputeFixed32Size(int32_t fieldNumber, uint32_t value) + __attribute__((const)); +size_t GPBComputeBoolSize(int32_t fieldNumber, BOOL value) + __attribute__((const)); +size_t GPBComputeStringSize(int32_t fieldNumber, NSString *value) + __attribute__((const)); +size_t GPBComputeGroupSize(int32_t fieldNumber, GPBMessage *value) + __attribute__((const)); +size_t GPBComputeUnknownGroupSize(int32_t fieldNumber, + GPBUnknownFieldSet *value) + __attribute__((const)); +size_t GPBComputeMessageSize(int32_t fieldNumber, GPBMessage *value) + __attribute__((const)); +size_t GPBComputeDataSize(int32_t fieldNumber, NSData *value) + __attribute__((const)); +size_t GPBComputeUInt32Size(int32_t fieldNumber, uint32_t value) + __attribute__((const)); +size_t GPBComputeSFixed32Size(int32_t fieldNumber, int32_t value) + __attribute__((const)); +size_t GPBComputeSFixed64Size(int32_t fieldNumber, int64_t value) + __attribute__((const)); +size_t GPBComputeSInt32Size(int32_t fieldNumber, int32_t value) + __attribute__((const)); +size_t GPBComputeSInt64Size(int32_t fieldNumber, int64_t value) + __attribute__((const)); +size_t GPBComputeTagSize(int32_t fieldNumber) __attribute__((const)); +size_t GPBComputeWireFormatTagSize(int field_number, GPBType type) + __attribute__((const)); + +size_t GPBComputeDoubleSizeNoTag(double value) __attribute__((const)); +size_t GPBComputeFloatSizeNoTag(float value) __attribute__((const)); +size_t GPBComputeUInt64SizeNoTag(uint64_t value) __attribute__((const)); +size_t GPBComputeInt64SizeNoTag(int64_t value) __attribute__((const)); +size_t GPBComputeInt32SizeNoTag(int32_t value) __attribute__((const)); +size_t GPBComputeFixed64SizeNoTag(uint64_t value) __attribute__((const)); +size_t GPBComputeFixed32SizeNoTag(uint32_t value) __attribute__((const)); +size_t GPBComputeBoolSizeNoTag(BOOL value) __attribute__((const)); +size_t GPBComputeStringSizeNoTag(NSString *value) __attribute__((const)); +size_t GPBComputeGroupSizeNoTag(GPBMessage *value) __attribute__((const)); +size_t GPBComputeUnknownGroupSizeNoTag(GPBUnknownFieldSet *value) + __attribute__((const)); +size_t GPBComputeMessageSizeNoTag(GPBMessage *value) __attribute__((const)); +size_t GPBComputeDataSizeNoTag(NSData *value) __attribute__((const)); +size_t GPBComputeUInt32SizeNoTag(int32_t value) __attribute__((const)); +size_t GPBComputeEnumSizeNoTag(int32_t value) __attribute__((const)); +size_t GPBComputeSFixed32SizeNoTag(int32_t value) __attribute__((const)); +size_t GPBComputeSFixed64SizeNoTag(int64_t value) __attribute__((const)); +size_t GPBComputeSInt32SizeNoTag(int32_t value) __attribute__((const)); +size_t GPBComputeSInt64SizeNoTag(int64_t value) __attribute__((const)); + +// Note that this will calculate the size of 64 bit values truncated to 32. +size_t GPBComputeSizeTSizeAsInt32NoTag(size_t value) __attribute__((const)); + +size_t GPBComputeRawVarint32Size(int32_t value) __attribute__((const)); +size_t GPBComputeRawVarint64Size(int64_t value) __attribute__((const)); + +// Note that this will calculate the size of 64 bit values truncated to 32. +size_t GPBComputeRawVarint32SizeForInteger(NSInteger value) + __attribute__((const)); + +// Compute the number of bytes that would be needed to encode a +// MessageSet extension to the stream. For historical reasons, +// the wire format differs from normal fields. +size_t GPBComputeMessageSetExtensionSize(int32_t fieldNumber, GPBMessage *value) + __attribute__((const)); + +// Compute the number of bytes that would be needed to encode an +// unparsed MessageSet extension field to the stream. For +// historical reasons, the wire format differs from normal fields. +size_t GPBComputeRawMessageSetExtensionSize(int32_t fieldNumber, NSData *value) + __attribute__((const)); + +size_t GPBComputeEnumSize(int32_t fieldNumber, int32_t value) + __attribute__((const)); + +CF_EXTERN_C_END + +// Write methods for types that can be in packed arrays. +//%PDDM-DEFINE _WRITE_PACKABLE_DECLS(NAME, ARRAY_TYPE, TYPE) +//%- (void)write##NAME:(int32_t)fieldNumber value:(TYPE)value; +//%- (void)write##NAME##s:(int32_t)fieldNumber +//% NAME$S values:(GPB##ARRAY_TYPE##Array *)values +//% NAME$S tag:(uint32_t)tag; +//%- (void)write##NAME##NoTag:(TYPE)value; +//% +// Write methods for types that aren't in packed arrays. +//%PDDM-DEFINE _WRITE_UNPACKABLE_DECLS(NAME, TYPE) +//%- (void)write##NAME:(int32_t)fieldNumber value:(TYPE)value; +//%- (void)write##NAME##s:(int32_t)fieldNumber values:(NSArray *)values; +//%- (void)write##NAME##NoTag:(TYPE)value; +//% +// Special write methods for Groups. +//%PDDM-DEFINE _WRITE_GROUP_DECLS(NAME, TYPE) +//%- (void)write##NAME:(int32_t)fieldNumber +//% NAME$S value:(TYPE)value; +//%- (void)write##NAME##s:(int32_t)fieldNumber values:(NSArray *)values; +//%- (void)write##NAME##NoTag:(int32_t)fieldNumber +//% NAME$S value:(TYPE)value; +//% + +// One macro to hide it all up above. +//%PDDM-DEFINE _WRITE_DECLS() +//%_WRITE_PACKABLE_DECLS(Double, Double, double) +//%_WRITE_PACKABLE_DECLS(Float, Float, float) +//%_WRITE_PACKABLE_DECLS(UInt64, UInt64, uint64_t) +//%_WRITE_PACKABLE_DECLS(Int64, Int64, int64_t) +//%_WRITE_PACKABLE_DECLS(Int32, Int32, int32_t) +//%_WRITE_PACKABLE_DECLS(UInt32, UInt32, uint32_t) +//%_WRITE_PACKABLE_DECLS(Fixed64, UInt64, uint64_t) +//%_WRITE_PACKABLE_DECLS(Fixed32, UInt32, uint32_t) +//%_WRITE_PACKABLE_DECLS(SInt32, Int32, int32_t) +//%_WRITE_PACKABLE_DECLS(SInt64, Int64, int64_t) +//%_WRITE_PACKABLE_DECLS(SFixed64, Int64, int64_t) +//%_WRITE_PACKABLE_DECLS(SFixed32, Int32, int32_t) +//%_WRITE_PACKABLE_DECLS(Bool, Bool, BOOL) +//%_WRITE_PACKABLE_DECLS(Enum, Enum, int32_t) +//%_WRITE_UNPACKABLE_DECLS(String, NSString *) +//%_WRITE_UNPACKABLE_DECLS(Message, GPBMessage *) +//%_WRITE_UNPACKABLE_DECLS(Data, NSData *) +//%_WRITE_GROUP_DECLS(Group, GPBMessage *) +//%_WRITE_GROUP_DECLS(UnknownGroup, GPBUnknownFieldSet *) diff --git a/objectivec/GPBCodedOutputStream.m b/objectivec/GPBCodedOutputStream.m new file mode 100644 index 00000000..9604c128 --- /dev/null +++ b/objectivec/GPBCodedOutputStream.m @@ -0,0 +1,1229 @@ +// 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. + +#import "GPBCodedOutputStream.h" + +#import <mach/vm_param.h> + +#import "GPBArray.h" +#import "GPBUnknownFieldSet_PackagePrivate.h" +#import "GPBUtilities_PackagePrivate.h" + +// Structure for containing state of a GPBCodedInputStream. Brought out into +// a struct so that we can inline several common functions instead of dealing +// with overhead of ObjC dispatch. +typedef struct GPBOutputBufferState { + uint8_t *bytes; + size_t size; + size_t position; + NSOutputStream *output; +} GPBOutputBufferState; + +@implementation GPBCodedOutputStream { + GPBOutputBufferState state_; + NSMutableData *buffer_; +} + +static const int32_t LITTLE_ENDIAN_32_SIZE = sizeof(uint32_t); +static const int32_t LITTLE_ENDIAN_64_SIZE = sizeof(uint64_t); + +// Internal helper that writes the current buffer to the output. The +// buffer position is reset to its initial value when this returns. +static void GPBRefreshBuffer(GPBOutputBufferState *state) { + if (state->output == nil) { + // We're writing to a single buffer. + [NSException raise:@"OutOfSpace" format:@""]; + } + if (state->position != 0) { + NSInteger written = + [state->output write:state->bytes maxLength:state->position]; + if (written != (NSInteger)state->position) { + [NSException raise:@"WriteFailed" format:@""]; + } + state->position = 0; + } +} + +static void GPBWriteRawByte(GPBOutputBufferState *state, uint8_t value) { + if (state->position == state->size) { + GPBRefreshBuffer(state); + } + state->bytes[state->position++] = value; +} + +static void GPBWriteRawVarint32(GPBOutputBufferState *state, int32_t value) { + while (YES) { + if ((value & ~0x7F) == 0) { + uint8_t val = (uint8_t)value; + GPBWriteRawByte(state, val); + return; + } else { + GPBWriteRawByte(state, (value & 0x7F) | 0x80); + value = GPBLogicalRightShift32(value, 7); + } + } +} + +static void GPBWriteRawVarint64(GPBOutputBufferState *state, int64_t value) { + while (YES) { + if ((value & ~0x7FL) == 0) { + uint8_t val = (uint8_t)value; + GPBWriteRawByte(state, val); + return; + } else { + GPBWriteRawByte(state, ((int32_t)value & 0x7F) | 0x80); + value = GPBLogicalRightShift64(value, 7); + } + } +} + +static void GPBWriteInt32NoTag(GPBOutputBufferState *state, int32_t value) { + if (value >= 0) { + GPBWriteRawVarint32(state, value); + } else { + // Must sign-extend + GPBWriteRawVarint64(state, value); + } +} + +static void GPBWriteUInt32(GPBOutputBufferState *state, int32_t fieldNumber, + uint32_t value) { + GPBWriteTagWithFormat(state, fieldNumber, GPBWireFormatVarint); + GPBWriteRawVarint32(state, value); +} + +static void GPBWriteTagWithFormat(GPBOutputBufferState *state, + uint32_t fieldNumber, GPBWireFormat format) { + GPBWriteRawVarint32(state, GPBWireFormatMakeTag(fieldNumber, format)); +} + +static void GPBWriteRawLittleEndian32(GPBOutputBufferState *state, + int32_t value) { + GPBWriteRawByte(state, (value)&0xFF); + GPBWriteRawByte(state, (value >> 8) & 0xFF); + GPBWriteRawByte(state, (value >> 16) & 0xFF); + GPBWriteRawByte(state, (value >> 24) & 0xFF); +} + +static void GPBWriteRawLittleEndian64(GPBOutputBufferState *state, + int64_t value) { + GPBWriteRawByte(state, (int32_t)(value)&0xFF); + GPBWriteRawByte(state, (int32_t)(value >> 8) & 0xFF); + GPBWriteRawByte(state, (int32_t)(value >> 16) & 0xFF); + GPBWriteRawByte(state, (int32_t)(value >> 24) & 0xFF); + GPBWriteRawByte(state, (int32_t)(value >> 32) & 0xFF); + GPBWriteRawByte(state, (int32_t)(value >> 40) & 0xFF); + GPBWriteRawByte(state, (int32_t)(value >> 48) & 0xFF); + GPBWriteRawByte(state, (int32_t)(value >> 56) & 0xFF); +} + +#if DEBUG && !defined(NS_BLOCK_ASSERTIONS) ++ (void)load { + // This test exists to verify that CFStrings with embedded NULLs will work + // for us. If this Assert fails, all code below that depends on + // CFStringGetCStringPtr will NOT work properly on strings that contain + // embedded NULLs, and we do get that in some protobufs. + // Note that this will not be compiled in release. + // We didn't feel that just keeping it in a unit test was sufficient because + // the Protobuf unit tests are only run when somebody is actually working + // on protobufs. + CFStringRef zeroTest = CFSTR("Test\0String"); + const char *cString = CFStringGetCStringPtr(zeroTest, kCFStringEncodingUTF8); + NSAssert(cString == NULL, @"Serious Error"); +} +#endif // DEBUG && !defined(NS_BLOCK_ASSERTIONS) + +- (void)dealloc { + [self flush]; + [state_.output close]; + [state_.output release]; + [buffer_ release]; + + [super dealloc]; +} + +- (instancetype)initWithOutputStream:(NSOutputStream *)output { + NSMutableData *data = [NSMutableData dataWithLength:PAGE_SIZE]; + return [self initWithOutputStream:output data:data]; +} + +- (instancetype)initWithData:(NSMutableData *)data { + return [self initWithOutputStream:nil data:data]; +} + +- (instancetype)initWithOutputStream:(NSOutputStream *)output + bufferSize:(size_t)bufferSize { + NSMutableData *data = [NSMutableData dataWithLength:bufferSize]; + return [self initWithOutputStream:output data:data]; +} + +- (instancetype)initWithOutputStream:(NSOutputStream *)output + data:(NSMutableData *)data { + if ((self = [super init])) { + buffer_ = [data retain]; + [output open]; + state_.bytes = [data mutableBytes]; + state_.size = [data length]; + state_.output = [output retain]; + } + return self; +} + ++ (instancetype)streamWithOutputStream:(NSOutputStream *)output + bufferSize:(size_t)bufferSize { + return [[[self alloc] initWithOutputStream:output + bufferSize:bufferSize] autorelease]; +} + ++ (instancetype)streamWithOutputStream:(NSOutputStream *)output { + return [[[self alloc] initWithOutputStream:output + bufferSize:PAGE_SIZE] autorelease]; +} + ++ (instancetype)streamWithData:(NSMutableData *)data { + return [[[self alloc] initWithData:data] autorelease]; +} + +- (void)writeDoubleNoTag:(double)value { + GPBWriteRawLittleEndian64(&state_, GPBConvertDoubleToInt64(value)); +} + +- (void)writeDouble:(int32_t)fieldNumber value:(double)value { + GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatFixed64); + GPBWriteRawLittleEndian64(&state_, GPBConvertDoubleToInt64(value)); +} + +- (void)writeFloatNoTag:(float)value { + GPBWriteRawLittleEndian32(&state_, GPBConvertFloatToInt32(value)); +} + +- (void)writeFloat:(int32_t)fieldNumber value:(float)value { + GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatFixed32); + GPBWriteRawLittleEndian32(&state_, GPBConvertFloatToInt32(value)); +} + +- (void)writeUInt64NoTag:(uint64_t)value { + GPBWriteRawVarint64(&state_, value); +} + +- (void)writeUInt64:(int32_t)fieldNumber value:(uint64_t)value { + GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatVarint); + GPBWriteRawVarint64(&state_, value); +} + +- (void)writeInt64NoTag:(int64_t)value { + GPBWriteRawVarint64(&state_, value); +} + +- (void)writeInt64:(int32_t)fieldNumber value:(int64_t)value { + GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatVarint); + GPBWriteRawVarint64(&state_, value); +} + +- (void)writeInt32NoTag:(int32_t)value { + GPBWriteInt32NoTag(&state_, value); +} + +- (void)writeInt32:(int32_t)fieldNumber value:(int32_t)value { + GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatVarint); + GPBWriteInt32NoTag(&state_, value); +} + +- (void)writeFixed64NoTag:(uint64_t)value { + GPBWriteRawLittleEndian64(&state_, value); +} + +- (void)writeFixed64:(int32_t)fieldNumber value:(uint64_t)value { + GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatFixed64); + GPBWriteRawLittleEndian64(&state_, value); +} + +- (void)writeFixed32NoTag:(uint32_t)value { + GPBWriteRawLittleEndian32(&state_, value); +} + +- (void)writeFixed32:(int32_t)fieldNumber value:(uint32_t)value { + GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatFixed32); + GPBWriteRawLittleEndian32(&state_, value); +} + +- (void)writeBoolNoTag:(BOOL)value { + GPBWriteRawByte(&state_, (value ? 1 : 0)); +} + +- (void)writeBool:(int32_t)fieldNumber value:(BOOL)value { + GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatVarint); + GPBWriteRawByte(&state_, (value ? 1 : 0)); +} + +- (void)writeStringNoTag:(const NSString *)value { + // If you are concerned about embedded NULLs see the test in + // +load above. + const char *quickString = + CFStringGetCStringPtr((CFStringRef)value, kCFStringEncodingUTF8); + size_t length = (quickString != NULL) + ? strlen(quickString) + : [value lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + GPBWriteRawVarint32(&state_, (int32_t)length); + + if (length == 0) { + return; + } + + // Fast path: Most strings are short, if the buffer already has space, + // add to it directly. + NSUInteger bufferBytesLeft = state_.size - state_.position; + if (bufferBytesLeft >= length) { + NSUInteger usedBufferLength = 0; + BOOL result; + if (quickString != NULL) { + memcpy(state_.bytes + state_.position, quickString, length); + usedBufferLength = length; + result = YES; + } else { + result = [value getBytes:state_.bytes + state_.position + maxLength:bufferBytesLeft + usedLength:&usedBufferLength + encoding:NSUTF8StringEncoding + options:0 + range:NSMakeRange(0, [value length]) + remainingRange:NULL]; + } + if (result) { + NSAssert2((usedBufferLength == length), + @"Our UTF8 calc was wrong? %tu vs %zd", usedBufferLength, + length); + state_.position += usedBufferLength; + return; + } + } else if (quickString != NULL) { + [self writeRawPtr:quickString offset:0 length:length]; + } else { + // Slow path: just get it as data and write it out. + NSData *utf8Data = [value dataUsingEncoding:NSUTF8StringEncoding]; + NSAssert2(([utf8Data length] == length), + @"Strings UTF8 length was wrong? %tu vs %zd", [utf8Data length], + length); + [self writeRawData:utf8Data]; + } +} + +- (void)writeString:(int32_t)fieldNumber value:(NSString *)value { + GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatLengthDelimited); + [self writeStringNoTag:value]; +} + +- (void)writeGroupNoTag:(int32_t)fieldNumber value:(GPBMessage *)value { + [value writeToCodedOutputStream:self]; + GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatEndGroup); +} + +- (void)writeGroup:(int32_t)fieldNumber value:(GPBMessage *)value { + GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatStartGroup); + [self writeGroupNoTag:fieldNumber value:value]; +} + +- (void)writeUnknownGroupNoTag:(int32_t)fieldNumber + value:(const GPBUnknownFieldSet *)value { + [value writeToCodedOutputStream:self]; + GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatEndGroup); +} + +- (void)writeUnknownGroup:(int32_t)fieldNumber + value:(GPBUnknownFieldSet *)value { + GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatStartGroup); + [self writeUnknownGroupNoTag:fieldNumber value:value]; +} + +- (void)writeMessageNoTag:(GPBMessage *)value { + GPBWriteRawVarint32(&state_, (int32_t)[value serializedSize]); + [value writeToCodedOutputStream:self]; +} + +- (void)writeMessage:(int32_t)fieldNumber value:(GPBMessage *)value { + GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatLengthDelimited); + [self writeMessageNoTag:value]; +} + +- (void)writeDataNoTag:(NSData *)value { + GPBWriteRawVarint32(&state_, (int32_t)[value length]); + [self writeRawData:value]; +} + +- (void)writeData:(int32_t)fieldNumber value:(NSData *)value { + GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatLengthDelimited); + [self writeDataNoTag:value]; +} + +- (void)writeUInt32NoTag:(uint32_t)value { + GPBWriteRawVarint32(&state_, value); +} + +- (void)writeUInt32:(int32_t)fieldNumber value:(uint32_t)value { + GPBWriteUInt32(&state_, fieldNumber, value); +} + +- (void)writeEnumNoTag:(int32_t)value { + GPBWriteRawVarint32(&state_, value); +} + +- (void)writeEnum:(int32_t)fieldNumber value:(int32_t)value { + GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatVarint); + GPBWriteRawVarint32(&state_, value); +} + +- (void)writeSFixed32NoTag:(int32_t)value { + GPBWriteRawLittleEndian32(&state_, value); +} + +- (void)writeSFixed32:(int32_t)fieldNumber value:(int32_t)value { + GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatFixed32); + GPBWriteRawLittleEndian32(&state_, value); +} + +- (void)writeSFixed64NoTag:(int64_t)value { + GPBWriteRawLittleEndian64(&state_, value); +} + +- (void)writeSFixed64:(int32_t)fieldNumber value:(int64_t)value { + GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatFixed64); + GPBWriteRawLittleEndian64(&state_, value); +} + +- (void)writeSInt32NoTag:(int32_t)value { + GPBWriteRawVarint32(&state_, GPBEncodeZigZag32(value)); +} + +- (void)writeSInt32:(int32_t)fieldNumber value:(int32_t)value { + GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatVarint); + GPBWriteRawVarint32(&state_, GPBEncodeZigZag32(value)); +} + +- (void)writeSInt64NoTag:(int64_t)value { + GPBWriteRawVarint64(&state_, GPBEncodeZigZag64(value)); +} + +- (void)writeSInt64:(int32_t)fieldNumber value:(int64_t)value { + GPBWriteTagWithFormat(&state_, fieldNumber, GPBWireFormatVarint); + GPBWriteRawVarint64(&state_, GPBEncodeZigZag64(value)); +} + +//%PDDM-DEFINE WRITE_PACKABLE_DEFNS(NAME, ARRAY_TYPE, TYPE, ACCESSOR_NAME) +//%- (void)write##NAME##s:(int32_t)fieldNumber +//% NAME$S values:(GPB##ARRAY_TYPE##Array *)values +//% NAME$S tag:(uint32_t)tag { +//% if (tag != 0) { +//% if (values.count == 0) return; +//% __block size_t dataSize = 0; +//% [values enumerate##ACCESSOR_NAME##ValuesWithBlock:^(TYPE value, NSUInteger idx, BOOL *stop) { +//%#pragma unused(idx, stop) +//% dataSize += GPBCompute##NAME##SizeNoTag(value); +//% }]; +//% GPBWriteRawVarint32(&state_, tag); +//% GPBWriteRawVarint32(&state_, (int32_t)dataSize); +//% [values enumerate##ACCESSOR_NAME##ValuesWithBlock:^(TYPE value, NSUInteger idx, BOOL *stop) { +//%#pragma unused(idx, stop) +//% [self write##NAME##NoTag:value]; +//% }]; +//% } else { +//% [values enumerate##ACCESSOR_NAME##ValuesWithBlock:^(TYPE value, NSUInteger idx, BOOL *stop) { +//%#pragma unused(idx, stop) +//% [self write##NAME:fieldNumber value:value]; +//% }]; +//% } +//%} +//% +//%PDDM-DEFINE WRITE_UNPACKABLE_DEFNS(NAME, TYPE) +//%- (void)write##NAME##s:(int32_t)fieldNumber values:(NSArray *)values { +//% for (TYPE *value in values) { +//% [self write##NAME:fieldNumber value:value]; +//% } +//%} +//% +//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(Double, Double, double, ) +// This block of code is generated, do not edit it directly. + +- (void)writeDoubles:(int32_t)fieldNumber + values:(GPBDoubleArray *)values + tag:(uint32_t)tag { + if (tag != 0) { + if (values.count == 0) return; + __block size_t dataSize = 0; + [values enumerateValuesWithBlock:^(double value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + dataSize += GPBComputeDoubleSizeNoTag(value); + }]; + GPBWriteRawVarint32(&state_, tag); + GPBWriteRawVarint32(&state_, (int32_t)dataSize); + [values enumerateValuesWithBlock:^(double value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeDoubleNoTag:value]; + }]; + } else { + [values enumerateValuesWithBlock:^(double value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeDouble:fieldNumber value:value]; + }]; + } +} + +//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(Float, Float, float, ) +// This block of code is generated, do not edit it directly. + +- (void)writeFloats:(int32_t)fieldNumber + values:(GPBFloatArray *)values + tag:(uint32_t)tag { + if (tag != 0) { + if (values.count == 0) return; + __block size_t dataSize = 0; + [values enumerateValuesWithBlock:^(float value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + dataSize += GPBComputeFloatSizeNoTag(value); + }]; + GPBWriteRawVarint32(&state_, tag); + GPBWriteRawVarint32(&state_, (int32_t)dataSize); + [values enumerateValuesWithBlock:^(float value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeFloatNoTag:value]; + }]; + } else { + [values enumerateValuesWithBlock:^(float value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeFloat:fieldNumber value:value]; + }]; + } +} + +//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(UInt64, UInt64, uint64_t, ) +// This block of code is generated, do not edit it directly. + +- (void)writeUInt64s:(int32_t)fieldNumber + values:(GPBUInt64Array *)values + tag:(uint32_t)tag { + if (tag != 0) { + if (values.count == 0) return; + __block size_t dataSize = 0; + [values enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + dataSize += GPBComputeUInt64SizeNoTag(value); + }]; + GPBWriteRawVarint32(&state_, tag); + GPBWriteRawVarint32(&state_, (int32_t)dataSize); + [values enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeUInt64NoTag:value]; + }]; + } else { + [values enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeUInt64:fieldNumber value:value]; + }]; + } +} + +//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(Int64, Int64, int64_t, ) +// This block of code is generated, do not edit it directly. + +- (void)writeInt64s:(int32_t)fieldNumber + values:(GPBInt64Array *)values + tag:(uint32_t)tag { + if (tag != 0) { + if (values.count == 0) return; + __block size_t dataSize = 0; + [values enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + dataSize += GPBComputeInt64SizeNoTag(value); + }]; + GPBWriteRawVarint32(&state_, tag); + GPBWriteRawVarint32(&state_, (int32_t)dataSize); + [values enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeInt64NoTag:value]; + }]; + } else { + [values enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeInt64:fieldNumber value:value]; + }]; + } +} + +//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(Int32, Int32, int32_t, ) +// This block of code is generated, do not edit it directly. + +- (void)writeInt32s:(int32_t)fieldNumber + values:(GPBInt32Array *)values + tag:(uint32_t)tag { + if (tag != 0) { + if (values.count == 0) return; + __block size_t dataSize = 0; + [values enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + dataSize += GPBComputeInt32SizeNoTag(value); + }]; + GPBWriteRawVarint32(&state_, tag); + GPBWriteRawVarint32(&state_, (int32_t)dataSize); + [values enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeInt32NoTag:value]; + }]; + } else { + [values enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeInt32:fieldNumber value:value]; + }]; + } +} + +//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(UInt32, UInt32, uint32_t, ) +// This block of code is generated, do not edit it directly. + +- (void)writeUInt32s:(int32_t)fieldNumber + values:(GPBUInt32Array *)values + tag:(uint32_t)tag { + if (tag != 0) { + if (values.count == 0) return; + __block size_t dataSize = 0; + [values enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + dataSize += GPBComputeUInt32SizeNoTag(value); + }]; + GPBWriteRawVarint32(&state_, tag); + GPBWriteRawVarint32(&state_, (int32_t)dataSize); + [values enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeUInt32NoTag:value]; + }]; + } else { + [values enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeUInt32:fieldNumber value:value]; + }]; + } +} + +//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(Fixed64, UInt64, uint64_t, ) +// This block of code is generated, do not edit it directly. + +- (void)writeFixed64s:(int32_t)fieldNumber + values:(GPBUInt64Array *)values + tag:(uint32_t)tag { + if (tag != 0) { + if (values.count == 0) return; + __block size_t dataSize = 0; + [values enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + dataSize += GPBComputeFixed64SizeNoTag(value); + }]; + GPBWriteRawVarint32(&state_, tag); + GPBWriteRawVarint32(&state_, (int32_t)dataSize); + [values enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeFixed64NoTag:value]; + }]; + } else { + [values enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeFixed64:fieldNumber value:value]; + }]; + } +} + +//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(Fixed32, UInt32, uint32_t, ) +// This block of code is generated, do not edit it directly. + +- (void)writeFixed32s:(int32_t)fieldNumber + values:(GPBUInt32Array *)values + tag:(uint32_t)tag { + if (tag != 0) { + if (values.count == 0) return; + __block size_t dataSize = 0; + [values enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + dataSize += GPBComputeFixed32SizeNoTag(value); + }]; + GPBWriteRawVarint32(&state_, tag); + GPBWriteRawVarint32(&state_, (int32_t)dataSize); + [values enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeFixed32NoTag:value]; + }]; + } else { + [values enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeFixed32:fieldNumber value:value]; + }]; + } +} + +//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(SInt32, Int32, int32_t, ) +// This block of code is generated, do not edit it directly. + +- (void)writeSInt32s:(int32_t)fieldNumber + values:(GPBInt32Array *)values + tag:(uint32_t)tag { + if (tag != 0) { + if (values.count == 0) return; + __block size_t dataSize = 0; + [values enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + dataSize += GPBComputeSInt32SizeNoTag(value); + }]; + GPBWriteRawVarint32(&state_, tag); + GPBWriteRawVarint32(&state_, (int32_t)dataSize); + [values enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeSInt32NoTag:value]; + }]; + } else { + [values enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeSInt32:fieldNumber value:value]; + }]; + } +} + +//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(SInt64, Int64, int64_t, ) +// This block of code is generated, do not edit it directly. + +- (void)writeSInt64s:(int32_t)fieldNumber + values:(GPBInt64Array *)values + tag:(uint32_t)tag { + if (tag != 0) { + if (values.count == 0) return; + __block size_t dataSize = 0; + [values enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + dataSize += GPBComputeSInt64SizeNoTag(value); + }]; + GPBWriteRawVarint32(&state_, tag); + GPBWriteRawVarint32(&state_, (int32_t)dataSize); + [values enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeSInt64NoTag:value]; + }]; + } else { + [values enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeSInt64:fieldNumber value:value]; + }]; + } +} + +//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(SFixed64, Int64, int64_t, ) +// This block of code is generated, do not edit it directly. + +- (void)writeSFixed64s:(int32_t)fieldNumber + values:(GPBInt64Array *)values + tag:(uint32_t)tag { + if (tag != 0) { + if (values.count == 0) return; + __block size_t dataSize = 0; + [values enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + dataSize += GPBComputeSFixed64SizeNoTag(value); + }]; + GPBWriteRawVarint32(&state_, tag); + GPBWriteRawVarint32(&state_, (int32_t)dataSize); + [values enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeSFixed64NoTag:value]; + }]; + } else { + [values enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeSFixed64:fieldNumber value:value]; + }]; + } +} + +//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(SFixed32, Int32, int32_t, ) +// This block of code is generated, do not edit it directly. + +- (void)writeSFixed32s:(int32_t)fieldNumber + values:(GPBInt32Array *)values + tag:(uint32_t)tag { + if (tag != 0) { + if (values.count == 0) return; + __block size_t dataSize = 0; + [values enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + dataSize += GPBComputeSFixed32SizeNoTag(value); + }]; + GPBWriteRawVarint32(&state_, tag); + GPBWriteRawVarint32(&state_, (int32_t)dataSize); + [values enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeSFixed32NoTag:value]; + }]; + } else { + [values enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeSFixed32:fieldNumber value:value]; + }]; + } +} + +//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(Bool, Bool, BOOL, ) +// This block of code is generated, do not edit it directly. + +- (void)writeBools:(int32_t)fieldNumber + values:(GPBBoolArray *)values + tag:(uint32_t)tag { + if (tag != 0) { + if (values.count == 0) return; + __block size_t dataSize = 0; + [values enumerateValuesWithBlock:^(BOOL value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + dataSize += GPBComputeBoolSizeNoTag(value); + }]; + GPBWriteRawVarint32(&state_, tag); + GPBWriteRawVarint32(&state_, (int32_t)dataSize); + [values enumerateValuesWithBlock:^(BOOL value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeBoolNoTag:value]; + }]; + } else { + [values enumerateValuesWithBlock:^(BOOL value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeBool:fieldNumber value:value]; + }]; + } +} + +//%PDDM-EXPAND WRITE_PACKABLE_DEFNS(Enum, Enum, int32_t, Raw) +// This block of code is generated, do not edit it directly. + +- (void)writeEnums:(int32_t)fieldNumber + values:(GPBEnumArray *)values + tag:(uint32_t)tag { + if (tag != 0) { + if (values.count == 0) return; + __block size_t dataSize = 0; + [values enumerateRawValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + dataSize += GPBComputeEnumSizeNoTag(value); + }]; + GPBWriteRawVarint32(&state_, tag); + GPBWriteRawVarint32(&state_, (int32_t)dataSize); + [values enumerateRawValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeEnumNoTag:value]; + }]; + } else { + [values enumerateRawValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [self writeEnum:fieldNumber value:value]; + }]; + } +} + +//%PDDM-EXPAND WRITE_UNPACKABLE_DEFNS(String, NSString) +// This block of code is generated, do not edit it directly. + +- (void)writeStrings:(int32_t)fieldNumber values:(NSArray *)values { + for (NSString *value in values) { + [self writeString:fieldNumber value:value]; + } +} + +//%PDDM-EXPAND WRITE_UNPACKABLE_DEFNS(Message, GPBMessage) +// This block of code is generated, do not edit it directly. + +- (void)writeMessages:(int32_t)fieldNumber values:(NSArray *)values { + for (GPBMessage *value in values) { + [self writeMessage:fieldNumber value:value]; + } +} + +//%PDDM-EXPAND WRITE_UNPACKABLE_DEFNS(Data, NSData) +// This block of code is generated, do not edit it directly. + +- (void)writeDatas:(int32_t)fieldNumber values:(NSArray *)values { + for (NSData *value in values) { + [self writeData:fieldNumber value:value]; + } +} + +//%PDDM-EXPAND WRITE_UNPACKABLE_DEFNS(Group, GPBMessage) +// This block of code is generated, do not edit it directly. + +- (void)writeGroups:(int32_t)fieldNumber values:(NSArray *)values { + for (GPBMessage *value in values) { + [self writeGroup:fieldNumber value:value]; + } +} + +//%PDDM-EXPAND WRITE_UNPACKABLE_DEFNS(UnknownGroup, GPBUnknownFieldSet) +// This block of code is generated, do not edit it directly. + +- (void)writeUnknownGroups:(int32_t)fieldNumber values:(NSArray *)values { + for (GPBUnknownFieldSet *value in values) { + [self writeUnknownGroup:fieldNumber value:value]; + } +} + +//%PDDM-EXPAND-END (19 expansions) + +- (void)writeMessageSetExtension:(int32_t)fieldNumber + value:(GPBMessage *)value { + GPBWriteTagWithFormat(&state_, GPBWireFormatMessageSetItem, + GPBWireFormatStartGroup); + GPBWriteUInt32(&state_, GPBWireFormatMessageSetTypeId, fieldNumber); + [self writeMessage:GPBWireFormatMessageSetMessage value:value]; + GPBWriteTagWithFormat(&state_, GPBWireFormatMessageSetItem, + GPBWireFormatEndGroup); +} + +- (void)writeRawMessageSetExtension:(int32_t)fieldNumber value:(NSData *)value { + GPBWriteTagWithFormat(&state_, GPBWireFormatMessageSetItem, + GPBWireFormatStartGroup); + GPBWriteUInt32(&state_, GPBWireFormatMessageSetTypeId, fieldNumber); + [self writeData:GPBWireFormatMessageSetMessage value:value]; + GPBWriteTagWithFormat(&state_, GPBWireFormatMessageSetItem, + GPBWireFormatEndGroup); +} + +- (void)flush { + if (state_.output != nil) { + GPBRefreshBuffer(&state_); + } +} + +- (void)writeRawByte:(uint8_t)value { + GPBWriteRawByte(&state_, value); +} + +- (void)writeRawData:(const NSData *)data { + [self writeRawPtr:[data bytes] offset:0 length:[data length]]; +} + +- (void)writeRawPtr:(const void *)value + offset:(size_t)offset + length:(size_t)length { + if (value == nil || length == 0) { + return; + } + + NSUInteger bufferLength = state_.size; + NSUInteger bufferBytesLeft = bufferLength - state_.position; + if (bufferBytesLeft >= length) { + // We have room in the current buffer. + memcpy(state_.bytes + state_.position, ((uint8_t *)value) + offset, length); + state_.position += length; + } else { + // Write extends past current buffer. Fill the rest of this buffer and + // flush. + size_t bytesWritten = bufferBytesLeft; + memcpy(state_.bytes + state_.position, ((uint8_t *)value) + offset, + bytesWritten); + offset += bytesWritten; + length -= bytesWritten; + state_.position = bufferLength; + GPBRefreshBuffer(&state_); + bufferLength = state_.size; + + // Now deal with the rest. + // Since we have an output stream, this is our buffer + // and buffer offset == 0 + if (length <= bufferLength) { + // Fits in new buffer. + memcpy(state_.bytes, ((uint8_t *)value) + offset, length); + state_.position = length; + } else { + // Write is very big. Let's do it all at once. + [state_.output write:((uint8_t *)value) + offset maxLength:length]; + } + } +} + +- (void)writeTag:(uint32_t)fieldNumber format:(GPBWireFormat)format { + GPBWriteTagWithFormat(&state_, fieldNumber, format); +} + +- (void)writeRawVarint32:(int32_t)value { + GPBWriteRawVarint32(&state_, value); +} + +- (void)writeRawVarintSizeTAs32:(size_t)value { + // Note the truncation. + GPBWriteRawVarint32(&state_, (int32_t)value); +} + +- (void)writeRawVarint64:(int64_t)value { + GPBWriteRawVarint64(&state_, value); +} + +- (void)writeRawLittleEndian32:(int32_t)value { + GPBWriteRawLittleEndian32(&state_, value); +} + +- (void)writeRawLittleEndian64:(int64_t)value { + GPBWriteRawLittleEndian64(&state_, value); +} + +@end + +size_t GPBComputeDoubleSizeNoTag(Float64 value) { +#pragma unused(value) + return LITTLE_ENDIAN_64_SIZE; +} + +size_t GPBComputeFloatSizeNoTag(Float32 value) { +#pragma unused(value) + return LITTLE_ENDIAN_32_SIZE; +} + +size_t GPBComputeUInt64SizeNoTag(uint64_t value) { + return GPBComputeRawVarint64Size(value); +} + +size_t GPBComputeInt64SizeNoTag(int64_t value) { + return GPBComputeRawVarint64Size(value); +} + +size_t GPBComputeInt32SizeNoTag(int32_t value) { + if (value >= 0) { + return GPBComputeRawVarint32Size(value); + } else { + // Must sign-extend. + return 10; + } +} + +size_t GPBComputeSizeTSizeAsInt32NoTag(size_t value) { + return GPBComputeInt32SizeNoTag((int32_t)value); +} + +size_t GPBComputeFixed64SizeNoTag(uint64_t value) { +#pragma unused(value) + return LITTLE_ENDIAN_64_SIZE; +} + +size_t GPBComputeFixed32SizeNoTag(uint32_t value) { +#pragma unused(value) + return LITTLE_ENDIAN_32_SIZE; +} + +size_t GPBComputeBoolSizeNoTag(BOOL value) { +#pragma unused(value) + return 1; +} + +size_t GPBComputeStringSizeNoTag(NSString *value) { + // If you are concerned about embedded NULLs see the test in + // +load above. + const char *quickString = + CFStringGetCStringPtr((CFStringRef)value, kCFStringEncodingUTF8); + NSUInteger length = + (quickString != NULL) + ? strlen(quickString) + : [value lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + return GPBComputeRawVarint32SizeForInteger(length) + length; +} + +size_t GPBComputeGroupSizeNoTag(GPBMessage *value) { + return [value serializedSize]; +} + +size_t GPBComputeUnknownGroupSizeNoTag(GPBUnknownFieldSet *value) { + return value.serializedSize; +} + +size_t GPBComputeMessageSizeNoTag(GPBMessage *value) { + size_t size = [value serializedSize]; + return GPBComputeRawVarint32SizeForInteger(size) + size; +} + +size_t GPBComputeDataSizeNoTag(NSData *value) { + NSUInteger valueLength = [value length]; + return GPBComputeRawVarint32SizeForInteger(valueLength) + valueLength; +} + +size_t GPBComputeUInt32SizeNoTag(int32_t value) { + return GPBComputeRawVarint32Size(value); +} + +size_t GPBComputeEnumSizeNoTag(int32_t value) { + return GPBComputeRawVarint32Size(value); +} + +size_t GPBComputeSFixed32SizeNoTag(int32_t value) { +#pragma unused(value) + return LITTLE_ENDIAN_32_SIZE; +} + +size_t GPBComputeSFixed64SizeNoTag(int64_t value) { +#pragma unused(value) + return LITTLE_ENDIAN_64_SIZE; +} + +size_t GPBComputeSInt32SizeNoTag(int32_t value) { + return GPBComputeRawVarint32Size(GPBEncodeZigZag32(value)); +} + +size_t GPBComputeSInt64SizeNoTag(int64_t value) { + return GPBComputeRawVarint64Size(GPBEncodeZigZag64(value)); +} + +size_t GPBComputeDoubleSize(int32_t fieldNumber, double value) { + return GPBComputeTagSize(fieldNumber) + GPBComputeDoubleSizeNoTag(value); +} + +size_t GPBComputeFloatSize(int32_t fieldNumber, float value) { + return GPBComputeTagSize(fieldNumber) + GPBComputeFloatSizeNoTag(value); +} + +size_t GPBComputeUInt64Size(int32_t fieldNumber, uint64_t value) { + return GPBComputeTagSize(fieldNumber) + GPBComputeUInt64SizeNoTag(value); +} + +size_t GPBComputeInt64Size(int32_t fieldNumber, int64_t value) { + return GPBComputeTagSize(fieldNumber) + GPBComputeInt64SizeNoTag(value); +} + +size_t GPBComputeInt32Size(int32_t fieldNumber, int32_t value) { + return GPBComputeTagSize(fieldNumber) + GPBComputeInt32SizeNoTag(value); +} + +size_t GPBComputeFixed64Size(int32_t fieldNumber, uint64_t value) { + return GPBComputeTagSize(fieldNumber) + GPBComputeFixed64SizeNoTag(value); +} + +size_t GPBComputeFixed32Size(int32_t fieldNumber, uint32_t value) { + return GPBComputeTagSize(fieldNumber) + GPBComputeFixed32SizeNoTag(value); +} + +size_t GPBComputeBoolSize(int32_t fieldNumber, BOOL value) { + return GPBComputeTagSize(fieldNumber) + GPBComputeBoolSizeNoTag(value); +} + +size_t GPBComputeStringSize(int32_t fieldNumber, NSString *value) { + return GPBComputeTagSize(fieldNumber) + GPBComputeStringSizeNoTag(value); +} + +size_t GPBComputeGroupSize(int32_t fieldNumber, GPBMessage *value) { + return GPBComputeTagSize(fieldNumber) * 2 + GPBComputeGroupSizeNoTag(value); +} + +size_t GPBComputeUnknownGroupSize(int32_t fieldNumber, + GPBUnknownFieldSet *value) { + return GPBComputeTagSize(fieldNumber) * 2 + + GPBComputeUnknownGroupSizeNoTag(value); +} + +size_t GPBComputeMessageSize(int32_t fieldNumber, GPBMessage *value) { + return GPBComputeTagSize(fieldNumber) + GPBComputeMessageSizeNoTag(value); +} + +size_t GPBComputeDataSize(int32_t fieldNumber, NSData *value) { + return GPBComputeTagSize(fieldNumber) + GPBComputeDataSizeNoTag(value); +} + +size_t GPBComputeUInt32Size(int32_t fieldNumber, uint32_t value) { + return GPBComputeTagSize(fieldNumber) + GPBComputeUInt32SizeNoTag(value); +} + +size_t GPBComputeEnumSize(int32_t fieldNumber, int32_t value) { + return GPBComputeTagSize(fieldNumber) + GPBComputeEnumSizeNoTag(value); +} + +size_t GPBComputeSFixed32Size(int32_t fieldNumber, int32_t value) { + return GPBComputeTagSize(fieldNumber) + GPBComputeSFixed32SizeNoTag(value); +} + +size_t GPBComputeSFixed64Size(int32_t fieldNumber, int64_t value) { + return GPBComputeTagSize(fieldNumber) + GPBComputeSFixed64SizeNoTag(value); +} + +size_t GPBComputeSInt32Size(int32_t fieldNumber, int32_t value) { + return GPBComputeTagSize(fieldNumber) + GPBComputeSInt32SizeNoTag(value); +} + +size_t GPBComputeSInt64Size(int32_t fieldNumber, int64_t value) { + return GPBComputeTagSize(fieldNumber) + + GPBComputeRawVarint64Size(GPBEncodeZigZag64(value)); +} + +size_t GPBComputeMessageSetExtensionSize(int32_t fieldNumber, + GPBMessage *value) { + return GPBComputeTagSize(GPBWireFormatMessageSetItem) * 2 + + GPBComputeUInt32Size(GPBWireFormatMessageSetTypeId, fieldNumber) + + GPBComputeMessageSize(GPBWireFormatMessageSetMessage, value); +} + +size_t GPBComputeRawMessageSetExtensionSize(int32_t fieldNumber, + NSData *value) { + return GPBComputeTagSize(GPBWireFormatMessageSetItem) * 2 + + GPBComputeUInt32Size(GPBWireFormatMessageSetTypeId, fieldNumber) + + GPBComputeDataSize(GPBWireFormatMessageSetMessage, value); +} + +size_t GPBComputeTagSize(int32_t fieldNumber) { + return GPBComputeRawVarint32Size( + GPBWireFormatMakeTag(fieldNumber, GPBWireFormatVarint)); +} + +size_t GPBComputeWireFormatTagSize(int field_number, GPBType type) { + size_t result = GPBComputeTagSize(field_number); + if (type == GPBTypeGroup) { + // Groups have both a start and an end tag. + return result * 2; + } else { + return result; + } +} + +size_t GPBComputeRawVarint32Size(int32_t value) { + // value is treated as unsigned, so it won't be sign-extended if negative. + if ((value & (0xffffffff << 7)) == 0) return 1; + if ((value & (0xffffffff << 14)) == 0) return 2; + if ((value & (0xffffffff << 21)) == 0) return 3; + if ((value & (0xffffffff << 28)) == 0) return 4; + return 5; +} + +size_t GPBComputeRawVarint32SizeForInteger(NSInteger value) { + // Note the truncation. + return GPBComputeRawVarint32Size((int32_t)value); +} + +size_t GPBComputeRawVarint64Size(int64_t value) { + if ((value & (0xffffffffffffffffL << 7)) == 0) return 1; + if ((value & (0xffffffffffffffffL << 14)) == 0) return 2; + if ((value & (0xffffffffffffffffL << 21)) == 0) return 3; + if ((value & (0xffffffffffffffffL << 28)) == 0) return 4; + if ((value & (0xffffffffffffffffL << 35)) == 0) return 5; + if ((value & (0xffffffffffffffffL << 42)) == 0) return 6; + if ((value & (0xffffffffffffffffL << 49)) == 0) return 7; + if ((value & (0xffffffffffffffffL << 56)) == 0) return 8; + if ((value & (0xffffffffffffffffL << 63)) == 0) return 9; + return 10; +} diff --git a/objectivec/GPBDescriptor.h b/objectivec/GPBDescriptor.h new file mode 100644 index 00000000..d8c369c1 --- /dev/null +++ b/objectivec/GPBDescriptor.h @@ -0,0 +1,143 @@ +// 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. + +#import <Foundation/Foundation.h> + +#import "GPBTypes.h" + +@class GPBEnumDescriptor; +@class GPBFieldDescriptor; +@class GPBFieldOptions; +@class GPBFileDescriptor; +@class GPBOneofDescriptor; + +typedef NS_ENUM(NSInteger, GPBFileSyntax) { + GPBFileSyntaxUnknown = 0, + GPBFileSyntaxProto2 = 2, + GPBFileSyntaxProto3 = 3, +}; + +typedef NS_ENUM(NSInteger, GPBFieldType) { + GPBFieldTypeSingle, // optional/required + GPBFieldTypeRepeated, // repeated + GPBFieldTypeMap, // map<K,V> +}; + +@interface GPBDescriptor : NSObject<NSCopying> + +@property(nonatomic, readonly, copy) NSString *name; +@property(nonatomic, readonly, strong) NSArray *fields; +@property(nonatomic, readonly, strong) NSArray *oneofs; +@property(nonatomic, readonly, strong) NSArray *enums; +@property(nonatomic, readonly, strong) NSArray *extensions; +@property(nonatomic, readonly) const GPBExtensionRange *extensionRanges; +@property(nonatomic, readonly) NSUInteger extensionRangesCount; +@property(nonatomic, readonly, assign) GPBFileDescriptor *file; + +@property(nonatomic, readonly, getter=isWireFormat) BOOL wireFormat; +@property(nonatomic, readonly) Class messageClass; + +- (GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber; +- (GPBFieldDescriptor *)fieldWithName:(NSString *)name; +- (GPBOneofDescriptor *)oneofWithName:(NSString *)name; +- (GPBEnumDescriptor *)enumWithName:(NSString *)name; +- (GPBFieldDescriptor *)extensionWithNumber:(uint32_t)fieldNumber; +- (GPBFieldDescriptor *)extensionWithName:(NSString *)name; + +@end + +@interface GPBFileDescriptor : NSObject + +@property(nonatomic, readonly, copy) NSString *package; +@property(nonatomic, readonly) GPBFileSyntax syntax; + +@end + +@interface GPBOneofDescriptor : NSObject +@property(nonatomic, readonly) NSString *name; +@property(nonatomic, readonly) NSArray *fields; + +- (GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber; +- (GPBFieldDescriptor *)fieldWithName:(NSString *)name; +@end + +@interface GPBFieldDescriptor : NSObject + +@property(nonatomic, readonly, copy) NSString *name; +@property(nonatomic, readonly) uint32_t number; +@property(nonatomic, readonly) GPBType type; +@property(nonatomic, readonly) BOOL hasDefaultValue; +@property(nonatomic, readonly) GPBValue defaultValue; +@property(nonatomic, readonly, getter=isRequired) BOOL required; +@property(nonatomic, readonly, getter=isOptional) BOOL optional; +@property(nonatomic, readonly) GPBFieldType fieldType; +// If it is a map, the value type is in -type. +@property(nonatomic, readonly) GPBType mapKeyType; +@property(nonatomic, readonly, getter=isPackable) BOOL packable; + +@property(nonatomic, readonly, assign) GPBOneofDescriptor *containingOneof; + +@property(nonatomic, readonly) GPBFieldOptions *fieldOptions; + +// Message properties +@property(nonatomic, readonly, assign) Class msgClass; + +// Enum properties +@property(nonatomic, readonly, strong) GPBEnumDescriptor *enumDescriptor; + +- (BOOL)isValidEnumValue:(int32_t)value; + +// For now, this will return nil if it doesn't know the name to use for +// TextFormat. +- (NSString *)textFormatName; + +@end + +@interface GPBEnumDescriptor : NSObject + +@property(nonatomic, readonly, copy) NSString *name; +@property(nonatomic, readonly) GPBEnumValidationFunc enumVerifier; + +- (NSString *)enumNameForValue:(int32_t)number; +- (BOOL)getValue:(int32_t *)outValue forEnumName:(NSString *)name; + +- (NSString *)textFormatNameForValue:(int32_t)number; + +@end + +@interface GPBExtensionDescriptor : NSObject +@property(nonatomic, readonly) uint32_t fieldNumber; +@property(nonatomic, readonly) GPBType type; +@property(nonatomic, readonly, getter=isRepeated) BOOL repeated; +@property(nonatomic, readonly, getter=isPackable) BOOL packable; +@property(nonatomic, readonly, assign) Class msgClass; +@property(nonatomic, readonly) NSString *singletonName; +@property(nonatomic, readonly, strong) GPBEnumDescriptor *enumDescriptor; +@end diff --git a/objectivec/GPBDescriptor.m b/objectivec/GPBDescriptor.m new file mode 100644 index 00000000..6730d532 --- /dev/null +++ b/objectivec/GPBDescriptor.m @@ -0,0 +1,888 @@ +// 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. + +#import "GPBDescriptor_PackagePrivate.h" + +#import <objc/runtime.h> + +#import "GPBUtilities_PackagePrivate.h" +#import "GPBWireFormat.h" +#import "GPBMessage_PackagePrivate.h" +#import "google/protobuf/Descriptor.pbobjc.h" + +// The address of this variable is used as a key for obj_getAssociatedObject. +static const char kTextFormatExtraValueKey = 0; + +// Utility function to generate selectors on the fly. +static SEL SelFromStrings(const char *prefix, const char *middle, + const char *suffix, BOOL takesArg) { + if (prefix == NULL && suffix == NULL && !takesArg) { + return sel_getUid(middle); + } + const size_t prefixLen = prefix != NULL ? strlen(prefix) : 0; + const size_t middleLen = strlen(middle); + const size_t suffixLen = suffix != NULL ? strlen(suffix) : 0; + size_t totalLen = + prefixLen + middleLen + suffixLen + 1; // include space for null on end. + if (takesArg) { + totalLen += 1; + } + char buffer[totalLen]; + if (prefix != NULL) { + memcpy(buffer, prefix, prefixLen); + memcpy(buffer + prefixLen, middle, middleLen); + buffer[prefixLen] = (char)toupper(buffer[prefixLen]); + } else { + memcpy(buffer, middle, middleLen); + } + if (suffix != NULL) { + memcpy(buffer + prefixLen + middleLen, suffix, suffixLen); + } + if (takesArg) { + buffer[totalLen - 2] = ':'; + } + // Always null terminate it. + buffer[totalLen - 1] = 0; + + SEL result = sel_getUid(buffer); + return result; +} + +static NSArray *NewFieldsArrayForHasIndex(int hasIndex, + NSArray *allMessageFields) + __attribute__((ns_returns_retained)); + +static NSArray *NewFieldsArrayForHasIndex(int hasIndex, + NSArray *allMessageFields) { + NSMutableArray *result = [[NSMutableArray alloc] init]; + for (GPBFieldDescriptor *fieldDesc in allMessageFields) { + if (fieldDesc->description_->hasIndex == hasIndex) { + [result addObject:fieldDesc]; + } + } + return result; +} + +@implementation GPBDescriptor { + Class messageClass_; + NSArray *enums_; + NSArray *extensions_; + GPBFileDescriptor *file_; + BOOL wireFormat_; +} + +@synthesize messageClass = messageClass_; +@synthesize fields = fields_; +@synthesize oneofs = oneofs_; +@synthesize enums = enums_; +@synthesize extensions = extensions_; +@synthesize extensionRanges = extensionRanges_; +@synthesize extensionRangesCount = extensionRangesCount_; +@synthesize file = file_; +@synthesize wireFormat = wireFormat_; + ++ (instancetype) + allocDescriptorForClass:(Class)messageClass + rootClass:(Class)rootClass + file:(GPBFileDescriptor *)file + fields:(GPBMessageFieldDescription *)fieldDescriptions + fieldCount:(NSUInteger)fieldCount + oneofs:(GPBMessageOneofDescription *)oneofDescriptions + oneofCount:(NSUInteger)oneofCount + enums:(GPBMessageEnumDescription *)enumDescriptions + enumCount:(NSUInteger)enumCount + ranges:(const GPBExtensionRange *)ranges + rangeCount:(NSUInteger)rangeCount + storageSize:(size_t)storageSize + wireFormat:(BOOL)wireFormat { + NSMutableArray *fields = nil; + NSMutableArray *oneofs = nil; + NSMutableArray *enums = nil; + NSMutableArray *extensionRanges = nil; + GPBFileSyntax syntax = file.syntax; + for (NSUInteger i = 0; i < fieldCount; ++i) { + if (fields == nil) { + fields = [[NSMutableArray alloc] initWithCapacity:fieldCount]; + } + GPBFieldDescriptor *fieldDescriptor = [[GPBFieldDescriptor alloc] + initWithFieldDescription:&fieldDescriptions[i] + rootClass:rootClass + syntax:syntax]; + [fields addObject:fieldDescriptor]; + [fieldDescriptor release]; + } + for (NSUInteger i = 0; i < oneofCount; ++i) { + if (oneofs == nil) { + oneofs = [[NSMutableArray alloc] initWithCapacity:oneofCount]; + } + GPBMessageOneofDescription *oneofDescription = &oneofDescriptions[i]; + NSArray *fieldsForOneof = + NewFieldsArrayForHasIndex(oneofDescription->index, fields); + GPBOneofDescriptor *oneofDescriptor = + [[GPBOneofDescriptor alloc] initWithOneofDescription:oneofDescription + fields:fieldsForOneof]; + [oneofs addObject:oneofDescriptor]; + [oneofDescriptor release]; + [fieldsForOneof release]; + } + for (NSUInteger i = 0; i < enumCount; ++i) { + if (enums == nil) { + enums = [[NSMutableArray alloc] initWithCapacity:enumCount]; + } + GPBEnumDescriptor *enumDescriptor = + enumDescriptions[i].enumDescriptorFunc(); + [enums addObject:enumDescriptor]; + } + + // TODO(dmaclach): Add support for extensions + GPBDescriptor *descriptor = [[self alloc] initWithClass:messageClass + file:file + fields:fields + oneofs:oneofs + enums:enums + extensions:nil + extensionRanges:ranges + extensionRangesCount:rangeCount + storageSize:storageSize + wireFormat:wireFormat]; + [fields release]; + [oneofs release]; + [enums release]; + [extensionRanges release]; + return descriptor; +} + ++ (instancetype) + allocDescriptorForClass:(Class)messageClass + rootClass:(Class)rootClass + file:(GPBFileDescriptor *)file + fields:(GPBMessageFieldDescription *)fieldDescriptions + fieldCount:(NSUInteger)fieldCount + oneofs:(GPBMessageOneofDescription *)oneofDescriptions + oneofCount:(NSUInteger)oneofCount + enums:(GPBMessageEnumDescription *)enumDescriptions + enumCount:(NSUInteger)enumCount + ranges:(const GPBExtensionRange *)ranges + rangeCount:(NSUInteger)rangeCount + storageSize:(size_t)storageSize + wireFormat:(BOOL)wireFormat + extraTextFormatInfo:(const char *)extraTextFormatInfo { + GPBDescriptor *descriptor = [self allocDescriptorForClass:messageClass + rootClass:rootClass + file:file + fields:fieldDescriptions + fieldCount:fieldCount + oneofs:oneofDescriptions + oneofCount:oneofCount + enums:enumDescriptions + enumCount:enumCount + ranges:ranges + rangeCount:rangeCount + storageSize:storageSize + wireFormat:wireFormat]; + // Extra info is a compile time option, so skip the work if not needed. + if (extraTextFormatInfo) { + NSValue *extraInfoValue = [NSValue valueWithPointer:extraTextFormatInfo]; + for (GPBFieldDescriptor *fieldDescriptor in descriptor->fields_) { + if (fieldDescriptor->description_->flags & GPBFieldTextFormatNameCustom) { + objc_setAssociatedObject(fieldDescriptor, &kTextFormatExtraValueKey, + extraInfoValue, + OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + } + } + return descriptor; +} + +- (instancetype)initWithClass:(Class)messageClass + file:(GPBFileDescriptor *)file + fields:(NSArray *)fields + oneofs:(NSArray *)oneofs + enums:(NSArray *)enums + extensions:(NSArray *)extensions + extensionRanges:(const GPBExtensionRange *)extensionRanges + extensionRangesCount:(NSUInteger)extensionRangesCount + storageSize:(size_t)storageSize + wireFormat:(BOOL)wireFormat { + if ((self = [super init])) { + messageClass_ = messageClass; + file_ = file; + fields_ = [fields retain]; + oneofs_ = [oneofs retain]; + enums_ = [enums retain]; + extensions_ = [extensions retain]; + extensionRanges_ = extensionRanges; + extensionRangesCount_ = extensionRangesCount; + storageSize_ = storageSize; + wireFormat_ = wireFormat; + } + return self; +} + +- (void)dealloc { + [fields_ release]; + [oneofs_ release]; + [enums_ release]; + [extensions_ release]; + [super dealloc]; +} + +- (NSString *)name { + return NSStringFromClass(messageClass_); +} + +- (id)copyWithZone:(NSZone *)zone { +#pragma unused(zone) + return [self retain]; +} + +- (GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber { + for (GPBFieldDescriptor *descriptor in fields_) { + if (GPBFieldNumber(descriptor) == fieldNumber) { + return descriptor; + } + } + return nil; +} + +- (GPBFieldDescriptor *)fieldWithName:(NSString *)name { + for (GPBFieldDescriptor *descriptor in fields_) { + if ([descriptor.name isEqual:name]) { + return descriptor; + } + } + return nil; +} + +- (GPBOneofDescriptor *)oneofWithName:(NSString *)name { + for (GPBOneofDescriptor *descriptor in oneofs_) { + if ([descriptor.name isEqual:name]) { + return descriptor; + } + } + return nil; +} + +- (GPBEnumDescriptor *)enumWithName:(NSString *)name { + for (GPBEnumDescriptor *descriptor in enums_) { + if ([descriptor.name isEqual:name]) { + return descriptor; + } + } + return nil; +} + +- (GPBFieldDescriptor *)extensionWithNumber:(uint32_t)fieldNumber { + for (GPBFieldDescriptor *descriptor in extensions_) { + if (GPBFieldNumber(descriptor) == fieldNumber) { + return descriptor; + } + } + return nil; +} + +- (GPBFieldDescriptor *)extensionWithName:(NSString *)name { + for (GPBFieldDescriptor *descriptor in extensions_) { + if ([descriptor.name isEqual:name]) { + return descriptor; + } + } + return nil; +} + +@end + +@implementation GPBFileDescriptor { + NSString *package_; + GPBFileSyntax syntax_; +} + +@synthesize package = package_; +@synthesize syntax = syntax_; + +- (instancetype)initWithPackage:(NSString *)package + syntax:(GPBFileSyntax)syntax { + self = [super init]; + if (self) { + package_ = [package copy]; + syntax_ = syntax; + } + return self; +} + +@end + +@implementation GPBOneofDescriptor + +@synthesize fields = fields_; + +- (instancetype)initWithOneofDescription: + (GPBMessageOneofDescription *)oneofDescription + fields:(NSArray *)fields { + self = [super init]; + if (self) { + NSAssert(oneofDescription->index < 0, @"Should always be <0"); + oneofDescription_ = oneofDescription; + fields_ = [fields retain]; + for (GPBFieldDescriptor *fieldDesc in fields) { + fieldDesc->containingOneof_ = self; + } + + caseSel_ = SelFromStrings(NULL, oneofDescription->name, "OneOfCase", NO); + } + return self; +} + +- (void)dealloc { + [fields_ release]; + [super dealloc]; +} + +- (NSString *)name { + return [NSString stringWithUTF8String:oneofDescription_->name]; +} + +- (GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber { + for (GPBFieldDescriptor *descriptor in fields_) { + if (GPBFieldNumber(descriptor) == fieldNumber) { + return descriptor; + } + } + return nil; +} + +- (GPBFieldDescriptor *)fieldWithName:(NSString *)name { + for (GPBFieldDescriptor *descriptor in fields_) { + if ([descriptor.name isEqual:name]) { + return descriptor; + } + } + return nil; +} + +@end + +uint32_t GPBFieldTag(GPBFieldDescriptor *self) { + GPBMessageFieldDescription *description = self->description_; + GPBWireFormat format; + if ((description->flags & GPBFieldMapKeyMask) != 0) { + // Maps are repeated messages on the wire. + format = GPBWireFormatForType(GPBTypeMessage, NO); + } else { + format = GPBWireFormatForType(description->type, + description->flags & GPBFieldPacked); + } + return GPBWireFormatMakeTag(description->number, format); +} + +@implementation GPBFieldDescriptor { + GPBValue defaultValue_; + GPBFieldOptions *fieldOptions_; + + // Message ivars + Class msgClass_; + + // Enum ivars. + // If protos are generated with GenerateEnumDescriptors on then it will + // be a enumDescriptor, otherwise it will be a enumVerifier. + union { + GPBEnumDescriptor *enumDescriptor_; + GPBEnumValidationFunc enumVerifier_; + } enumHandling_; +} + +@synthesize fieldOptions = fieldOptions_; +@synthesize msgClass = msgClass_; +@synthesize containingOneof = containingOneof_; + +- (instancetype)init { + // Throw an exception if people attempt to not use the designated initializer. + self = [super init]; + if (self != nil) { + [self doesNotRecognizeSelector:_cmd]; + self = nil; + } + return self; +} + +- (instancetype)initWithFieldDescription: + (GPBMessageFieldDescription *)description + rootClass:(Class)rootClass + syntax:(GPBFileSyntax)syntax { + if ((self = [super init])) { + description_ = description; + getSel_ = sel_getUid(description->name); + setSel_ = SelFromStrings("set", description->name, NULL, YES); + + if (description->fieldOptions) { + // FieldOptions stored as a length prefixed c-escaped string in descriptor + // records. + uint8_t *optionsBytes = (uint8_t *)description->fieldOptions; + uint32_t optionsLength = *((uint32_t *)optionsBytes); + // The length is stored in network byte order. + optionsLength = ntohl(optionsLength); + if (optionsLength > 0) { + optionsBytes += sizeof(optionsLength); + NSData *optionsData = [NSData dataWithBytesNoCopy:optionsBytes + length:optionsLength + freeWhenDone:NO]; + GPBExtensionRegistry *registry = [rootClass extensionRegistry]; + fieldOptions_ = [[GPBFieldOptions parseFromData:optionsData + extensionRegistry:registry] retain]; + } + } + + GPBType type = description->type; + BOOL isMessage = GPBTypeIsMessage(type); + if (isMessage) { + // No has* for repeated/map or something in a oneof (we can't check + // containingOneof_ because it isn't set until after initialization). + if ((description->hasIndex >= 0) && + (description->hasIndex != GPBNoHasBit)) { + hasSel_ = SelFromStrings("has", description->name, NULL, NO); + setHasSel_ = SelFromStrings("setHas", description->name, NULL, YES); + } + const char *className = description->typeSpecific.className; + msgClass_ = objc_getClass(className); + NSAssert1(msgClass_, @"Class %s not defined", className); + // The defaultValue_ is fetched directly in -defaultValue to avoid + // initialization order issues. + } else { + if (!GPBFieldIsMapOrArray(self)) { + defaultValue_ = description->defaultValue; + if (type == GPBTypeData) { + // Data stored as a length prefixed c-string in descriptor records. + const uint8_t *bytes = (const uint8_t *)defaultValue_.valueData; + if (bytes) { + uint32_t length = *((uint32_t *)bytes); + // The length is stored in network byte order. + length = ntohl(length); + bytes += sizeof(length); + defaultValue_.valueData = + [[NSData alloc] initWithBytes:bytes length:length]; + } + } + // No has* methods for proto3 or if our hasIndex is < 0 because it + // means the field is in a oneof (we can't check containingOneof_ + // because it isn't set until after initialization). + if ((syntax != GPBFileSyntaxProto3) && (description->hasIndex >= 0) && + (description->hasIndex != GPBNoHasBit)) { + hasSel_ = SelFromStrings("has", description->name, NULL, NO); + setHasSel_ = SelFromStrings("setHas", description->name, NULL, YES); + } + } + if (GPBTypeIsEnum(type)) { + if (description_->flags & GPBFieldHasEnumDescriptor) { + enumHandling_.enumDescriptor_ = + description->typeSpecific.enumDescFunc(); + } else { + enumHandling_.enumVerifier_ = description->typeSpecific.enumVerifier; + } + } + } + } + return self; +} + +- (void)dealloc { + if (description_->type == GPBTypeData && + !(description_->flags & GPBFieldRepeated)) { + [defaultValue_.valueData release]; + } + [super dealloc]; +} + +- (GPBType)type { + return description_->type; +} + +- (BOOL)hasDefaultValue { + return (description_->flags & GPBFieldHasDefaultValue) != 0; +} + +- (uint32_t)number { + return description_->number; +} + +- (NSString *)name { + return [NSString stringWithUTF8String:description_->name]; +} + +- (BOOL)isRequired { + return (description_->flags & GPBFieldRequired) != 0; +} + +- (BOOL)isOptional { + return (description_->flags & GPBFieldOptional) != 0; +} + +- (GPBFieldType)fieldType { + GPBFieldFlags flags = description_->flags; + if ((flags & GPBFieldRepeated) != 0) { + return GPBFieldTypeRepeated; + } else if ((flags & GPBFieldMapKeyMask) != 0) { + return GPBFieldTypeMap; + } else { + return GPBFieldTypeSingle; + } +} + +- (GPBType)mapKeyType { + switch (description_->flags & GPBFieldMapKeyMask) { + case GPBFieldMapKeyInt32: + return GPBTypeInt32; + case GPBFieldMapKeyInt64: + return GPBTypeInt64; + case GPBFieldMapKeyUInt32: + return GPBTypeUInt32; + case GPBFieldMapKeyUInt64: + return GPBTypeUInt64; + case GPBFieldMapKeySInt32: + return GPBTypeSInt32; + case GPBFieldMapKeySInt64: + return GPBTypeSInt64; + case GPBFieldMapKeyFixed32: + return GPBTypeFixed32; + case GPBFieldMapKeyFixed64: + return GPBTypeFixed64; + case GPBFieldMapKeySFixed32: + return GPBTypeSFixed32; + case GPBFieldMapKeySFixed64: + return GPBTypeSFixed64; + case GPBFieldMapKeyBool: + return GPBTypeBool; + case GPBFieldMapKeyString: + return GPBTypeString; + + default: + NSAssert(0, @"Not a map type"); + return GPBTypeInt32; // For lack of anything better. + } +} + +- (BOOL)isPackable { + return (description_->flags & GPBFieldPacked) != 0; +} + +- (BOOL)isValidEnumValue:(int32_t)value { + NSAssert(description_->type == GPBTypeEnum, + @"Field Must be of type GPBTypeEnum"); + if (description_->flags & GPBFieldHasEnumDescriptor) { + return enumHandling_.enumDescriptor_.enumVerifier(value); + } else { + return enumHandling_.enumVerifier_(value); + } +} + +- (GPBEnumDescriptor *)enumDescriptor { + if (description_->flags & GPBFieldHasEnumDescriptor) { + return enumHandling_.enumDescriptor_; + } else { + return nil; + } +} + +- (GPBValue)defaultValue { + // Depends on the fact that defaultValue_ is initialized either to "0/nil" or + // to an actual defaultValue in our initializer. + GPBValue value = defaultValue_; + + if (!(description_->flags & GPBFieldRepeated)) { + // We special handle data and strings. If they are nil, we replace them + // with empty string/empty data. + GPBType type = description_->type; + if (type == GPBTypeData && value.valueData == nil) { + value.valueData = GPBEmptyNSData(); + } else if (type == GPBTypeString && value.valueString == nil) { + value.valueString = @""; + } + } + return value; +} + +- (NSString *)textFormatName { + if ((description_->flags & GPBFieldTextFormatNameCustom) != 0) { + NSValue *extraInfoValue = + objc_getAssociatedObject(self, &kTextFormatExtraValueKey); + // Support can be left out at generation time. + if (!extraInfoValue) { + return nil; + } + const uint8_t *extraTextFormatInfo = [extraInfoValue pointerValue]; + return GPBDecodeTextFormatName(extraTextFormatInfo, GPBFieldNumber(self), + self.name); + } + + // The logic here has to match SetCommonFieldVariables() from + // objectivec_field.cc in the proto compiler. + NSString *name = self.name; + NSUInteger len = [name length]; + + // Remove the "_p" added to reserved names. + if ([name hasSuffix:@"_p"]) { + name = [name substringToIndex:(len - 2)]; + len = [name length]; + } + + // Remove "Array" from the end for repeated fields. + if (((description_->flags & GPBFieldRepeated) != 0) && + [name hasSuffix:@"Array"]) { + name = [name substringToIndex:(len - 5)]; + len = [name length]; + } + + // Groups vs. other fields. + if (description_->type == GPBTypeGroup) { + // Just capitalize the first letter. + unichar firstChar = [name characterAtIndex:0]; + if (firstChar >= 'a' && firstChar <= 'z') { + NSString *firstCharString = + [NSString stringWithFormat:@"%C", (unichar)(firstChar - 'a' + 'A')]; + NSString *result = + [name stringByReplacingCharactersInRange:NSMakeRange(0, 1) + withString:firstCharString]; + return result; + } + return name; + + } else { + // Undo the CamelCase. + NSMutableString *result = [NSMutableString stringWithCapacity:len]; + for (NSUInteger i = 0; i < len; i++) { + unichar c = [name characterAtIndex:i]; + if (c >= 'A' && c <= 'Z') { + if (i > 0) { + [result appendFormat:@"_%C", (unichar)(c - 'A' + 'a')]; + } else { + [result appendFormat:@"%C", c]; + } + } else { + [result appendFormat:@"%C", c]; + } + } + return result; + } +} + +@end + +@implementation GPBEnumDescriptor { + NSString *name_; + GPBMessageEnumValueDescription *valueDescriptions_; + NSUInteger valueDescriptionsCount_; + GPBEnumValidationFunc enumVerifier_; + const uint8_t *extraTextFormatInfo_; +} + +@synthesize name = name_; +@synthesize enumVerifier = enumVerifier_; + ++ (instancetype) + allocDescriptorForName:(NSString *)name + values:(GPBMessageEnumValueDescription *)valueDescriptions + valueCount:(NSUInteger)valueCount + enumVerifier:(GPBEnumValidationFunc)enumVerifier { + GPBEnumDescriptor *descriptor = [[self alloc] initWithName:name + values:valueDescriptions + valueCount:valueCount + enumVerifier:enumVerifier]; + return descriptor; +} + ++ (instancetype) + allocDescriptorForName:(NSString *)name + values:(GPBMessageEnumValueDescription *)valueDescriptions + valueCount:(NSUInteger)valueCount + enumVerifier:(GPBEnumValidationFunc)enumVerifier + extraTextFormatInfo:(const char *)extraTextFormatInfo { + // Call the common case. + GPBEnumDescriptor *descriptor = [self allocDescriptorForName:name + values:valueDescriptions + valueCount:valueCount + enumVerifier:enumVerifier]; + // Set the extra info. + descriptor->extraTextFormatInfo_ = (const uint8_t *)extraTextFormatInfo; + return descriptor; +} + +- (instancetype)initWithName:(NSString *)name + values:(GPBMessageEnumValueDescription *)valueDescriptions + valueCount:(NSUInteger)valueCount + enumVerifier:(GPBEnumValidationFunc)enumVerifier { + if ((self = [super init])) { + name_ = [name copy]; + valueDescriptions_ = valueDescriptions; + valueDescriptionsCount_ = valueCount; + enumVerifier_ = enumVerifier; + } + return self; +} + +- (NSString *)enumNameForValue:(int32_t)number { + for (NSUInteger i = 0; i < valueDescriptionsCount_; ++i) { + GPBMessageEnumValueDescription *scan = &valueDescriptions_[i]; + if ((scan->number == number) && (scan->name != NULL)) { + NSString *fullName = + [NSString stringWithFormat:@"%@_%s", name_, scan->name]; + return fullName; + } + } + return nil; +} + +- (BOOL)getValue:(int32_t *)outValue forEnumName:(NSString *)name { + // Must have the prefix. + NSUInteger prefixLen = name_.length + 1; + if ((name.length <= prefixLen) || ![name hasPrefix:name_] || + ([name characterAtIndex:prefixLen - 1] != '_')) { + return NO; + } + + // Skip over the prefix. + const char *nameAsCStr = [name UTF8String]; + nameAsCStr += prefixLen; + + // Find it. + for (NSUInteger i = 0; i < valueDescriptionsCount_; ++i) { + GPBMessageEnumValueDescription *scan = &valueDescriptions_[i]; + if ((scan->name != NULL) && (strcmp(nameAsCStr, scan->name) == 0)) { + if (outValue) { + *outValue = scan->number; + } + return YES; + } + } + return NO; +} + +- (void)dealloc { + [name_ release]; + [super dealloc]; +} + +- (NSString *)textFormatNameForValue:(int32_t)number { + // Find the EnumValue descriptor and its index. + GPBMessageEnumValueDescription *valueDescriptor = NULL; + NSUInteger valueDescriptorIndex; + for (valueDescriptorIndex = 0; valueDescriptorIndex < valueDescriptionsCount_; + ++valueDescriptorIndex) { + GPBMessageEnumValueDescription *scan = + &valueDescriptions_[valueDescriptorIndex]; + if (scan->number == number) { + valueDescriptor = scan; + break; + } + } + + // If we didn't find it, or names were disable at proto compile time, nothing + // we can do. + if (!valueDescriptor || !valueDescriptor->name) { + return nil; + } + + NSString *result = nil; + // Naming adds an underscore between enum name and value name, skip that also. + NSString *shortName = [NSString stringWithUTF8String:valueDescriptor->name]; + + // See if it is in the map of special format handling. + if (extraTextFormatInfo_) { + result = GPBDecodeTextFormatName(extraTextFormatInfo_, + (int32_t)valueDescriptorIndex, shortName); + } + // Logic here needs to match what objectivec_enum.cc does in the proto + // compiler. + if (result == nil) { + NSUInteger len = [shortName length]; + NSMutableString *worker = [NSMutableString stringWithCapacity:len]; + for (NSUInteger i = 0; i < len; i++) { + unichar c = [shortName characterAtIndex:i]; + if (i > 0 && c >= 'A' && c <= 'Z') { + [worker appendString:@"_"]; + } + [worker appendFormat:@"%c", toupper((char)c)]; + } + result = worker; + } + return result; +} + +@end + +@implementation GPBExtensionDescriptor + +- (instancetype)initWithExtensionDescription: + (GPBExtensionDescription *)description { + if ((self = [super init])) { + description_ = description; + } + return self; +} + +- (NSString *)singletonName { + return [NSString stringWithUTF8String:description_->singletonName]; +} + +- (const char *)singletonNameC { + return description_->singletonName; +} + +- (uint32_t)fieldNumber { + return description_->fieldNumber; +} + +- (GPBType)type { + return description_->type; +} + +- (BOOL)isRepeated { + return (description_->options & GPBExtensionRepeated) != 0; +} + +- (BOOL)isMap { + return (description_->options & GPBFieldMapKeyMask) != 0; +} + +- (BOOL)isPackable { + return (description_->options & GPBExtensionPacked) != 0; +} + +- (Class)msgClass { + return objc_getClass(description_->messageOrGroupClassName); +} + +- (GPBEnumDescriptor *)enumDescriptor { + if (GPBTypeIsEnum(description_->type)) { + GPBEnumDescriptor *enumDescriptor = description_->enumDescriptorFunc(); + return enumDescriptor; + } + return nil; +} + +@end diff --git a/objectivec/GPBDescriptor_PackagePrivate.h b/objectivec/GPBDescriptor_PackagePrivate.h new file mode 100644 index 00000000..acb4fe70 --- /dev/null +++ b/objectivec/GPBDescriptor_PackagePrivate.h @@ -0,0 +1,293 @@ +// 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. + +// This header is private to the ProtobolBuffers library and must NOT be +// included by any sources outside this library. The contents of this file are +// subject to change at any time without notice. + +#import "GPBDescriptor.h" + +// Describes attributes of the field. +typedef NS_OPTIONS(uint32_t, GPBFieldFlags) { + // These map to standard protobuf concepts. + GPBFieldRequired = 1 << 0, + GPBFieldRepeated = 1 << 1, + GPBFieldPacked = 1 << 2, + GPBFieldOptional = 1 << 3, + GPBFieldHasDefaultValue = 1 << 4, + + // These are not standard protobuf concepts, they are specific to the + // Objective C runtime. + + // These bits are used to mark the field as a map and what the key + // type is. + GPBFieldMapKeyMask = 0xF << 8, + GPBFieldMapKeyInt32 = 1 << 8, + GPBFieldMapKeyInt64 = 2 << 8, + GPBFieldMapKeyUInt32 = 3 << 8, + GPBFieldMapKeyUInt64 = 4 << 8, + GPBFieldMapKeySInt32 = 5 << 8, + GPBFieldMapKeySInt64 = 6 << 8, + GPBFieldMapKeyFixed32 = 7 << 8, + GPBFieldMapKeyFixed64 = 8 << 8, + GPBFieldMapKeySFixed32 = 9 << 8, + GPBFieldMapKeySFixed64 = 10 << 8, + GPBFieldMapKeyBool = 11 << 8, + GPBFieldMapKeyString = 12 << 8, + + // Indicates the field needs custom handling for the TextFormat name, if not + // set, the name can be derived from the ObjC name. + GPBFieldTextFormatNameCustom = 1 << 16, + // Indicates the field has an enum descriptor. + // TODO(thomasvl): Output the CPP check to use descFunc or validator based + // on final compile. This will then get added based on that. + GPBFieldHasEnumDescriptor = 1 << 17, +}; + +// Describes a single field in a protobuf as it is represented as an ivar. +typedef struct GPBMessageFieldDescription { + // Name of ivar. + const char *name; + // The field number for the ivar. + uint32_t number; + // The index (in bits) into _has_storage_. + // > 0: the bit to use for a value being set. + // = 0: no storage used. + // < 0: in a oneOf, use a full int32 to record the field active. + int32_t hasIndex; + // Field flags. Use accessor functions below. + GPBFieldFlags flags; + // Type of the ivar. + GPBType type; + // Offset of the variable into it's structure struct. + size_t offset; + // FieldOptions protobuf, serialized as string. + const char *fieldOptions; + + GPBValue defaultValue; // Default value for the ivar. + union { + const char *className; // Name for message class. + // For enums only: If EnumDescriptors are compiled in, it will be that, + // otherwise it will be the verifier. + GPBEnumDescriptorFunc enumDescFunc; + GPBEnumValidationFunc enumVerifier; + } typeSpecific; +} GPBMessageFieldDescription; + +// Describes a oneof. +typedef struct GPBMessageOneofDescription { + // Name of this enum oneof. + const char *name; + // The index of this oneof in the has_storage. + int32_t index; +} GPBMessageOneofDescription; + +// Describes an enum type defined in a .proto file. +typedef struct GPBMessageEnumDescription { + GPBEnumDescriptorFunc enumDescriptorFunc; +} GPBMessageEnumDescription; + +// Describes an individual enum constant of a particular type. +typedef struct GPBMessageEnumValueDescription { + // Name of this enum constant. + const char *name; + // Numeric value of this enum constant. + int32_t number; +} GPBMessageEnumValueDescription; + +// Describes attributes of the extension. +typedef NS_OPTIONS(uint32_t, GPBExtensionOptions) { + // These map to standard protobuf concepts. + GPBExtensionRepeated = 1 << 0, + GPBExtensionPacked = 1 << 1, + GPBExtensionSetWireFormat = 1 << 2, +}; + +// An extension +typedef struct GPBExtensionDescription { + const char *singletonName; + GPBType type; + const char *extendedClass; + int32_t fieldNumber; + GPBValue defaultValue; + const char *messageOrGroupClassName; + GPBExtensionOptions options; + GPBEnumDescriptorFunc enumDescriptorFunc; +} GPBExtensionDescription; + +@interface GPBDescriptor () { + @package + NSArray *fields_; + NSArray *oneofs_; + size_t storageSize_; +} + +// fieldDescriptions, enumDescriptions, rangeDescriptions, and +// extraTextFormatInfo have to be long lived, they are held as raw pointers. ++ (instancetype) + allocDescriptorForClass:(Class)messageClass + rootClass:(Class)rootClass + file:(GPBFileDescriptor *)file + fields:(GPBMessageFieldDescription *)fieldDescriptions + fieldCount:(NSUInteger)fieldCount + oneofs:(GPBMessageOneofDescription *)oneofDescriptions + oneofCount:(NSUInteger)oneofCount + enums:(GPBMessageEnumDescription *)enumDescriptions + enumCount:(NSUInteger)enumCount + ranges:(const GPBExtensionRange *)ranges + rangeCount:(NSUInteger)rangeCount + storageSize:(size_t)storageSize + wireFormat:(BOOL)wireFormat; ++ (instancetype) + allocDescriptorForClass:(Class)messageClass + rootClass:(Class)rootClass + file:(GPBFileDescriptor *)file + fields:(GPBMessageFieldDescription *)fieldDescriptions + fieldCount:(NSUInteger)fieldCount + oneofs:(GPBMessageOneofDescription *)oneofDescriptions + oneofCount:(NSUInteger)oneofCount + enums:(GPBMessageEnumDescription *)enumDescriptions + enumCount:(NSUInteger)enumCount + ranges:(const GPBExtensionRange *)ranges + rangeCount:(NSUInteger)rangeCount + storageSize:(size_t)storageSize + wireFormat:(BOOL)wireFormat + extraTextFormatInfo:(const char *)extraTextFormatInfo; + +- (instancetype)initWithClass:(Class)messageClass + file:(GPBFileDescriptor *)file + fields:(NSArray *)fields + oneofs:(NSArray *)oneofs + enums:(NSArray *)enums + extensions:(NSArray *)extensions + extensionRanges:(const GPBExtensionRange *)ranges + extensionRangesCount:(NSUInteger)rangeCount + storageSize:(size_t)storage + wireFormat:(BOOL)wireFormat; + +@end + +@interface GPBFileDescriptor () +- (instancetype)initWithPackage:(NSString *)package + syntax:(GPBFileSyntax)syntax; +@end + +@interface GPBOneofDescriptor () { + @package + GPBMessageOneofDescription *oneofDescription_; + NSArray *fields_; + + SEL caseSel_; +} +- (instancetype)initWithOneofDescription: + (GPBMessageOneofDescription *)oneofDescription + fields:(NSArray *)fields; +@end + +@interface GPBFieldDescriptor () { + @package + GPBMessageFieldDescription *description_; + GPB_UNSAFE_UNRETAINED GPBOneofDescriptor *containingOneof_; + + SEL getSel_; + SEL setSel_; + SEL hasSel_; + SEL setHasSel_; +} + +// Single initializer +// description has to be long lived, it is held as a raw pointer. +- (instancetype)initWithFieldDescription: + (GPBMessageFieldDescription *)description + rootClass:(Class)rootClass + syntax:(GPBFileSyntax)syntax; +@end + +@interface GPBEnumDescriptor () +// valueDescriptions and extraTextFormatInfo have to be long lived, they are +// held as raw pointers. ++ (instancetype) + allocDescriptorForName:(NSString *)name + values:(GPBMessageEnumValueDescription *)valueDescriptions + valueCount:(NSUInteger)valueCount + enumVerifier:(GPBEnumValidationFunc)enumVerifier; ++ (instancetype) + allocDescriptorForName:(NSString *)name + values:(GPBMessageEnumValueDescription *)valueDescriptions + valueCount:(NSUInteger)valueCount + enumVerifier:(GPBEnumValidationFunc)enumVerifier + extraTextFormatInfo:(const char *)extraTextFormatInfo; + +- (instancetype)initWithName:(NSString *)name + values:(GPBMessageEnumValueDescription *)valueDescriptions + valueCount:(NSUInteger)valueCount + enumVerifier:(GPBEnumValidationFunc)enumVerifier; +@end + +@interface GPBExtensionDescriptor () { + @package + GPBExtensionDescription *description_; +} + +// description has to be long lived, it is held as a raw pointer. +- (instancetype)initWithExtensionDescription: + (GPBExtensionDescription *)description; +@end + +CF_EXTERN_C_BEGIN + +GPB_INLINE BOOL GPBFieldIsMapOrArray(GPBFieldDescriptor *field) { + return (field->description_->flags & + (GPBFieldRepeated | GPBFieldMapKeyMask)) != 0; +} + +GPB_INLINE GPBType GPBGetFieldType(GPBFieldDescriptor *field) { + return field->description_->type; +} + +GPB_INLINE int32_t GPBFieldHasIndex(GPBFieldDescriptor *field) { + return field->description_->hasIndex; +} + +GPB_INLINE uint32_t GPBFieldNumber(GPBFieldDescriptor *field) { + return field->description_->number; +} + +uint32_t GPBFieldTag(GPBFieldDescriptor *self); + +GPB_INLINE BOOL GPBPreserveUnknownFields(GPBFileSyntax syntax) { + return syntax != GPBFileSyntaxProto3; +} + +GPB_INLINE BOOL GPBHasPreservingUnknownEnumSemantics(GPBFileSyntax syntax) { + return syntax == GPBFileSyntaxProto3; +} + +CF_EXTERN_C_END diff --git a/objectivec/GPBDictionary.h b/objectivec/GPBDictionary.h new file mode 100644 index 00000000..72873ad2 --- /dev/null +++ b/objectivec/GPBDictionary.h @@ -0,0 +1,2233 @@ +// 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. + +#import <Foundation/Foundation.h> + +#import "GPBTypes.h" + +// These classes are used for map fields of basic data types. They are used because +// they perform better than boxing into NSNumbers in NSDictionaries. + +// Note: These are not meant to be subclassed. + +//%PDDM-EXPAND DECLARE_DICTIONARIES() +// This block of code is generated, do not edit it directly. + +#pragma mark - UInt32 -> UInt32 + +@interface GPBUInt32UInt32Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(uint32_t)value + forKey:(uint32_t)key; ++ (instancetype)dictionaryWithValues:(const uint32_t [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBUInt32UInt32Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const uint32_t [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBUInt32UInt32Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(uint32_t)key value:(uint32_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint32_t key, uint32_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBUInt32UInt32Dictionary *)otherDictionary; + +- (void)setValue:(uint32_t)value forKey:(uint32_t)key; + +- (void)removeValueForKey:(uint32_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - UInt32 -> Int32 + +@interface GPBUInt32Int32Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(int32_t)value + forKey:(uint32_t)key; ++ (instancetype)dictionaryWithValues:(const int32_t [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBUInt32Int32Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBUInt32Int32Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(uint32_t)key value:(int32_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint32_t key, int32_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBUInt32Int32Dictionary *)otherDictionary; + +- (void)setValue:(int32_t)value forKey:(uint32_t)key; + +- (void)removeValueForKey:(uint32_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - UInt32 -> UInt64 + +@interface GPBUInt32UInt64Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(uint64_t)value + forKey:(uint32_t)key; ++ (instancetype)dictionaryWithValues:(const uint64_t [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBUInt32UInt64Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const uint64_t [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBUInt32UInt64Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(uint32_t)key value:(uint64_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint32_t key, uint64_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBUInt32UInt64Dictionary *)otherDictionary; + +- (void)setValue:(uint64_t)value forKey:(uint32_t)key; + +- (void)removeValueForKey:(uint32_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - UInt32 -> Int64 + +@interface GPBUInt32Int64Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(int64_t)value + forKey:(uint32_t)key; ++ (instancetype)dictionaryWithValues:(const int64_t [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBUInt32Int64Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const int64_t [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBUInt32Int64Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(uint32_t)key value:(int64_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint32_t key, int64_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBUInt32Int64Dictionary *)otherDictionary; + +- (void)setValue:(int64_t)value forKey:(uint32_t)key; + +- (void)removeValueForKey:(uint32_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - UInt32 -> Bool + +@interface GPBUInt32BoolDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(BOOL)value + forKey:(uint32_t)key; ++ (instancetype)dictionaryWithValues:(const BOOL [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBUInt32BoolDictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const BOOL [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBUInt32BoolDictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(uint32_t)key value:(BOOL *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint32_t key, BOOL value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBUInt32BoolDictionary *)otherDictionary; + +- (void)setValue:(BOOL)value forKey:(uint32_t)key; + +- (void)removeValueForKey:(uint32_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - UInt32 -> Float + +@interface GPBUInt32FloatDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(float)value + forKey:(uint32_t)key; ++ (instancetype)dictionaryWithValues:(const float [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBUInt32FloatDictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const float [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBUInt32FloatDictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(uint32_t)key value:(float *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint32_t key, float value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBUInt32FloatDictionary *)otherDictionary; + +- (void)setValue:(float)value forKey:(uint32_t)key; + +- (void)removeValueForKey:(uint32_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - UInt32 -> Double + +@interface GPBUInt32DoubleDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(double)value + forKey:(uint32_t)key; ++ (instancetype)dictionaryWithValues:(const double [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBUInt32DoubleDictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const double [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBUInt32DoubleDictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(uint32_t)key value:(double *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint32_t key, double value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBUInt32DoubleDictionary *)otherDictionary; + +- (void)setValue:(double)value forKey:(uint32_t)key; + +- (void)removeValueForKey:(uint32_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - UInt32 -> Enum + +@interface GPBUInt32EnumDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; +@property(nonatomic, readonly) GPBEnumValidationFunc validationFunc; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValue:(int32_t)rawValue + forKey:(uint32_t)key; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBUInt32EnumDictionary *)dictionary; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems; + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func; +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBUInt32EnumDictionary *)dictionary; +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems; + +// These will return kGPBUnrecognizedEnumeratorValue if the value for the key +// is not a valid enumerator as defined by validationFunc. If the actual value is +// desired, use "raw" version of the method. + +- (BOOL)valueForKey:(uint32_t)key value:(int32_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint32_t key, int32_t value, BOOL *stop))block; + +// These methods bypass the validationFunc to provide access to values that were not +// known at the time the binary was compiled. + +- (BOOL)valueForKey:(uint32_t)key rawValue:(int32_t *)rawValue; + +- (void)enumerateKeysAndRawValuesUsingBlock: + (void (^)(uint32_t key, int32_t rawValue, BOOL *stop))block; + +- (void)addRawEntriesFromDictionary:(GPBUInt32EnumDictionary *)otherDictionary; + +// If value is not a valid enumerator as defined by validationFunc, these +// methods will assert in debug, and will log in release and assign the value +// to the default value. Use the rawValue methods below to assign non enumerator +// values. + +- (void)setValue:(int32_t)value forKey:(uint32_t)key; + +// This method bypass the validationFunc to provide setting of values that were not +// known at the time the binary was compiled. +- (void)setRawValue:(int32_t)rawValue forKey:(uint32_t)key; + +// No validation applies to these methods. + +- (void)removeValueForKey:(uint32_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - UInt32 -> Object + +@interface GPBUInt32ObjectDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(id)value + forKey:(uint32_t)key; ++ (instancetype)dictionaryWithValues:(const id GPB_UNSAFE_UNRETAINED [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBUInt32ObjectDictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const id GPB_UNSAFE_UNRETAINED [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBUInt32ObjectDictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (id)valueForKey:(uint32_t)key; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint32_t key, id value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBUInt32ObjectDictionary *)otherDictionary; + +- (void)setValue:(id)value forKey:(uint32_t)key; + +- (void)removeValueForKey:(uint32_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - Int32 -> UInt32 + +@interface GPBInt32UInt32Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(uint32_t)value + forKey:(int32_t)key; ++ (instancetype)dictionaryWithValues:(const uint32_t [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBInt32UInt32Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const uint32_t [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBInt32UInt32Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(int32_t)key value:(uint32_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int32_t key, uint32_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBInt32UInt32Dictionary *)otherDictionary; + +- (void)setValue:(uint32_t)value forKey:(int32_t)key; + +- (void)removeValueForKey:(int32_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - Int32 -> Int32 + +@interface GPBInt32Int32Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(int32_t)value + forKey:(int32_t)key; ++ (instancetype)dictionaryWithValues:(const int32_t [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBInt32Int32Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBInt32Int32Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(int32_t)key value:(int32_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int32_t key, int32_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBInt32Int32Dictionary *)otherDictionary; + +- (void)setValue:(int32_t)value forKey:(int32_t)key; + +- (void)removeValueForKey:(int32_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - Int32 -> UInt64 + +@interface GPBInt32UInt64Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(uint64_t)value + forKey:(int32_t)key; ++ (instancetype)dictionaryWithValues:(const uint64_t [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBInt32UInt64Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const uint64_t [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBInt32UInt64Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(int32_t)key value:(uint64_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int32_t key, uint64_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBInt32UInt64Dictionary *)otherDictionary; + +- (void)setValue:(uint64_t)value forKey:(int32_t)key; + +- (void)removeValueForKey:(int32_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - Int32 -> Int64 + +@interface GPBInt32Int64Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(int64_t)value + forKey:(int32_t)key; ++ (instancetype)dictionaryWithValues:(const int64_t [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBInt32Int64Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const int64_t [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBInt32Int64Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(int32_t)key value:(int64_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int32_t key, int64_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBInt32Int64Dictionary *)otherDictionary; + +- (void)setValue:(int64_t)value forKey:(int32_t)key; + +- (void)removeValueForKey:(int32_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - Int32 -> Bool + +@interface GPBInt32BoolDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(BOOL)value + forKey:(int32_t)key; ++ (instancetype)dictionaryWithValues:(const BOOL [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBInt32BoolDictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const BOOL [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBInt32BoolDictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(int32_t)key value:(BOOL *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int32_t key, BOOL value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBInt32BoolDictionary *)otherDictionary; + +- (void)setValue:(BOOL)value forKey:(int32_t)key; + +- (void)removeValueForKey:(int32_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - Int32 -> Float + +@interface GPBInt32FloatDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(float)value + forKey:(int32_t)key; ++ (instancetype)dictionaryWithValues:(const float [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBInt32FloatDictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const float [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBInt32FloatDictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(int32_t)key value:(float *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int32_t key, float value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBInt32FloatDictionary *)otherDictionary; + +- (void)setValue:(float)value forKey:(int32_t)key; + +- (void)removeValueForKey:(int32_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - Int32 -> Double + +@interface GPBInt32DoubleDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(double)value + forKey:(int32_t)key; ++ (instancetype)dictionaryWithValues:(const double [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBInt32DoubleDictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const double [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBInt32DoubleDictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(int32_t)key value:(double *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int32_t key, double value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBInt32DoubleDictionary *)otherDictionary; + +- (void)setValue:(double)value forKey:(int32_t)key; + +- (void)removeValueForKey:(int32_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - Int32 -> Enum + +@interface GPBInt32EnumDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; +@property(nonatomic, readonly) GPBEnumValidationFunc validationFunc; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValue:(int32_t)rawValue + forKey:(int32_t)key; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBInt32EnumDictionary *)dictionary; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems; + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func; +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBInt32EnumDictionary *)dictionary; +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems; + +// These will return kGPBUnrecognizedEnumeratorValue if the value for the key +// is not a valid enumerator as defined by validationFunc. If the actual value is +// desired, use "raw" version of the method. + +- (BOOL)valueForKey:(int32_t)key value:(int32_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int32_t key, int32_t value, BOOL *stop))block; + +// These methods bypass the validationFunc to provide access to values that were not +// known at the time the binary was compiled. + +- (BOOL)valueForKey:(int32_t)key rawValue:(int32_t *)rawValue; + +- (void)enumerateKeysAndRawValuesUsingBlock: + (void (^)(int32_t key, int32_t rawValue, BOOL *stop))block; + +- (void)addRawEntriesFromDictionary:(GPBInt32EnumDictionary *)otherDictionary; + +// If value is not a valid enumerator as defined by validationFunc, these +// methods will assert in debug, and will log in release and assign the value +// to the default value. Use the rawValue methods below to assign non enumerator +// values. + +- (void)setValue:(int32_t)value forKey:(int32_t)key; + +// This method bypass the validationFunc to provide setting of values that were not +// known at the time the binary was compiled. +- (void)setRawValue:(int32_t)rawValue forKey:(int32_t)key; + +// No validation applies to these methods. + +- (void)removeValueForKey:(int32_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - Int32 -> Object + +@interface GPBInt32ObjectDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(id)value + forKey:(int32_t)key; ++ (instancetype)dictionaryWithValues:(const id GPB_UNSAFE_UNRETAINED [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBInt32ObjectDictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const id GPB_UNSAFE_UNRETAINED [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBInt32ObjectDictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (id)valueForKey:(int32_t)key; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int32_t key, id value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBInt32ObjectDictionary *)otherDictionary; + +- (void)setValue:(id)value forKey:(int32_t)key; + +- (void)removeValueForKey:(int32_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - UInt64 -> UInt32 + +@interface GPBUInt64UInt32Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(uint32_t)value + forKey:(uint64_t)key; ++ (instancetype)dictionaryWithValues:(const uint32_t [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBUInt64UInt32Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const uint32_t [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBUInt64UInt32Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(uint64_t)key value:(uint32_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint64_t key, uint32_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBUInt64UInt32Dictionary *)otherDictionary; + +- (void)setValue:(uint32_t)value forKey:(uint64_t)key; + +- (void)removeValueForKey:(uint64_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - UInt64 -> Int32 + +@interface GPBUInt64Int32Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(int32_t)value + forKey:(uint64_t)key; ++ (instancetype)dictionaryWithValues:(const int32_t [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBUInt64Int32Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBUInt64Int32Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(uint64_t)key value:(int32_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint64_t key, int32_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBUInt64Int32Dictionary *)otherDictionary; + +- (void)setValue:(int32_t)value forKey:(uint64_t)key; + +- (void)removeValueForKey:(uint64_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - UInt64 -> UInt64 + +@interface GPBUInt64UInt64Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(uint64_t)value + forKey:(uint64_t)key; ++ (instancetype)dictionaryWithValues:(const uint64_t [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBUInt64UInt64Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const uint64_t [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBUInt64UInt64Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(uint64_t)key value:(uint64_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint64_t key, uint64_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBUInt64UInt64Dictionary *)otherDictionary; + +- (void)setValue:(uint64_t)value forKey:(uint64_t)key; + +- (void)removeValueForKey:(uint64_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - UInt64 -> Int64 + +@interface GPBUInt64Int64Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(int64_t)value + forKey:(uint64_t)key; ++ (instancetype)dictionaryWithValues:(const int64_t [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBUInt64Int64Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const int64_t [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBUInt64Int64Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(uint64_t)key value:(int64_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint64_t key, int64_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBUInt64Int64Dictionary *)otherDictionary; + +- (void)setValue:(int64_t)value forKey:(uint64_t)key; + +- (void)removeValueForKey:(uint64_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - UInt64 -> Bool + +@interface GPBUInt64BoolDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(BOOL)value + forKey:(uint64_t)key; ++ (instancetype)dictionaryWithValues:(const BOOL [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBUInt64BoolDictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const BOOL [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBUInt64BoolDictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(uint64_t)key value:(BOOL *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint64_t key, BOOL value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBUInt64BoolDictionary *)otherDictionary; + +- (void)setValue:(BOOL)value forKey:(uint64_t)key; + +- (void)removeValueForKey:(uint64_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - UInt64 -> Float + +@interface GPBUInt64FloatDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(float)value + forKey:(uint64_t)key; ++ (instancetype)dictionaryWithValues:(const float [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBUInt64FloatDictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const float [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBUInt64FloatDictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(uint64_t)key value:(float *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint64_t key, float value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBUInt64FloatDictionary *)otherDictionary; + +- (void)setValue:(float)value forKey:(uint64_t)key; + +- (void)removeValueForKey:(uint64_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - UInt64 -> Double + +@interface GPBUInt64DoubleDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(double)value + forKey:(uint64_t)key; ++ (instancetype)dictionaryWithValues:(const double [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBUInt64DoubleDictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const double [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBUInt64DoubleDictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(uint64_t)key value:(double *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint64_t key, double value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBUInt64DoubleDictionary *)otherDictionary; + +- (void)setValue:(double)value forKey:(uint64_t)key; + +- (void)removeValueForKey:(uint64_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - UInt64 -> Enum + +@interface GPBUInt64EnumDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; +@property(nonatomic, readonly) GPBEnumValidationFunc validationFunc; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValue:(int32_t)rawValue + forKey:(uint64_t)key; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBUInt64EnumDictionary *)dictionary; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems; + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func; +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBUInt64EnumDictionary *)dictionary; +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems; + +// These will return kGPBUnrecognizedEnumeratorValue if the value for the key +// is not a valid enumerator as defined by validationFunc. If the actual value is +// desired, use "raw" version of the method. + +- (BOOL)valueForKey:(uint64_t)key value:(int32_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint64_t key, int32_t value, BOOL *stop))block; + +// These methods bypass the validationFunc to provide access to values that were not +// known at the time the binary was compiled. + +- (BOOL)valueForKey:(uint64_t)key rawValue:(int32_t *)rawValue; + +- (void)enumerateKeysAndRawValuesUsingBlock: + (void (^)(uint64_t key, int32_t rawValue, BOOL *stop))block; + +- (void)addRawEntriesFromDictionary:(GPBUInt64EnumDictionary *)otherDictionary; + +// If value is not a valid enumerator as defined by validationFunc, these +// methods will assert in debug, and will log in release and assign the value +// to the default value. Use the rawValue methods below to assign non enumerator +// values. + +- (void)setValue:(int32_t)value forKey:(uint64_t)key; + +// This method bypass the validationFunc to provide setting of values that were not +// known at the time the binary was compiled. +- (void)setRawValue:(int32_t)rawValue forKey:(uint64_t)key; + +// No validation applies to these methods. + +- (void)removeValueForKey:(uint64_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - UInt64 -> Object + +@interface GPBUInt64ObjectDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(id)value + forKey:(uint64_t)key; ++ (instancetype)dictionaryWithValues:(const id GPB_UNSAFE_UNRETAINED [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBUInt64ObjectDictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const id GPB_UNSAFE_UNRETAINED [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBUInt64ObjectDictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (id)valueForKey:(uint64_t)key; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint64_t key, id value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBUInt64ObjectDictionary *)otherDictionary; + +- (void)setValue:(id)value forKey:(uint64_t)key; + +- (void)removeValueForKey:(uint64_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - Int64 -> UInt32 + +@interface GPBInt64UInt32Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(uint32_t)value + forKey:(int64_t)key; ++ (instancetype)dictionaryWithValues:(const uint32_t [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBInt64UInt32Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const uint32_t [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBInt64UInt32Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(int64_t)key value:(uint32_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int64_t key, uint32_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBInt64UInt32Dictionary *)otherDictionary; + +- (void)setValue:(uint32_t)value forKey:(int64_t)key; + +- (void)removeValueForKey:(int64_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - Int64 -> Int32 + +@interface GPBInt64Int32Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(int32_t)value + forKey:(int64_t)key; ++ (instancetype)dictionaryWithValues:(const int32_t [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBInt64Int32Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBInt64Int32Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(int64_t)key value:(int32_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int64_t key, int32_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBInt64Int32Dictionary *)otherDictionary; + +- (void)setValue:(int32_t)value forKey:(int64_t)key; + +- (void)removeValueForKey:(int64_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - Int64 -> UInt64 + +@interface GPBInt64UInt64Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(uint64_t)value + forKey:(int64_t)key; ++ (instancetype)dictionaryWithValues:(const uint64_t [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBInt64UInt64Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const uint64_t [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBInt64UInt64Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(int64_t)key value:(uint64_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int64_t key, uint64_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBInt64UInt64Dictionary *)otherDictionary; + +- (void)setValue:(uint64_t)value forKey:(int64_t)key; + +- (void)removeValueForKey:(int64_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - Int64 -> Int64 + +@interface GPBInt64Int64Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(int64_t)value + forKey:(int64_t)key; ++ (instancetype)dictionaryWithValues:(const int64_t [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBInt64Int64Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const int64_t [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBInt64Int64Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(int64_t)key value:(int64_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int64_t key, int64_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBInt64Int64Dictionary *)otherDictionary; + +- (void)setValue:(int64_t)value forKey:(int64_t)key; + +- (void)removeValueForKey:(int64_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - Int64 -> Bool + +@interface GPBInt64BoolDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(BOOL)value + forKey:(int64_t)key; ++ (instancetype)dictionaryWithValues:(const BOOL [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBInt64BoolDictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const BOOL [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBInt64BoolDictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(int64_t)key value:(BOOL *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int64_t key, BOOL value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBInt64BoolDictionary *)otherDictionary; + +- (void)setValue:(BOOL)value forKey:(int64_t)key; + +- (void)removeValueForKey:(int64_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - Int64 -> Float + +@interface GPBInt64FloatDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(float)value + forKey:(int64_t)key; ++ (instancetype)dictionaryWithValues:(const float [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBInt64FloatDictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const float [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBInt64FloatDictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(int64_t)key value:(float *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int64_t key, float value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBInt64FloatDictionary *)otherDictionary; + +- (void)setValue:(float)value forKey:(int64_t)key; + +- (void)removeValueForKey:(int64_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - Int64 -> Double + +@interface GPBInt64DoubleDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(double)value + forKey:(int64_t)key; ++ (instancetype)dictionaryWithValues:(const double [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBInt64DoubleDictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const double [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBInt64DoubleDictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(int64_t)key value:(double *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int64_t key, double value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBInt64DoubleDictionary *)otherDictionary; + +- (void)setValue:(double)value forKey:(int64_t)key; + +- (void)removeValueForKey:(int64_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - Int64 -> Enum + +@interface GPBInt64EnumDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; +@property(nonatomic, readonly) GPBEnumValidationFunc validationFunc; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValue:(int32_t)rawValue + forKey:(int64_t)key; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBInt64EnumDictionary *)dictionary; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems; + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func; +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBInt64EnumDictionary *)dictionary; +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems; + +// These will return kGPBUnrecognizedEnumeratorValue if the value for the key +// is not a valid enumerator as defined by validationFunc. If the actual value is +// desired, use "raw" version of the method. + +- (BOOL)valueForKey:(int64_t)key value:(int32_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int64_t key, int32_t value, BOOL *stop))block; + +// These methods bypass the validationFunc to provide access to values that were not +// known at the time the binary was compiled. + +- (BOOL)valueForKey:(int64_t)key rawValue:(int32_t *)rawValue; + +- (void)enumerateKeysAndRawValuesUsingBlock: + (void (^)(int64_t key, int32_t rawValue, BOOL *stop))block; + +- (void)addRawEntriesFromDictionary:(GPBInt64EnumDictionary *)otherDictionary; + +// If value is not a valid enumerator as defined by validationFunc, these +// methods will assert in debug, and will log in release and assign the value +// to the default value. Use the rawValue methods below to assign non enumerator +// values. + +- (void)setValue:(int32_t)value forKey:(int64_t)key; + +// This method bypass the validationFunc to provide setting of values that were not +// known at the time the binary was compiled. +- (void)setRawValue:(int32_t)rawValue forKey:(int64_t)key; + +// No validation applies to these methods. + +- (void)removeValueForKey:(int64_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - Int64 -> Object + +@interface GPBInt64ObjectDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(id)value + forKey:(int64_t)key; ++ (instancetype)dictionaryWithValues:(const id GPB_UNSAFE_UNRETAINED [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBInt64ObjectDictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const id GPB_UNSAFE_UNRETAINED [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBInt64ObjectDictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (id)valueForKey:(int64_t)key; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int64_t key, id value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBInt64ObjectDictionary *)otherDictionary; + +- (void)setValue:(id)value forKey:(int64_t)key; + +- (void)removeValueForKey:(int64_t)aKey; +- (void)removeAll; + +@end + +#pragma mark - Bool -> UInt32 + +@interface GPBBoolUInt32Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(uint32_t)value + forKey:(BOOL)key; ++ (instancetype)dictionaryWithValues:(const uint32_t [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBBoolUInt32Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const uint32_t [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBBoolUInt32Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(BOOL)key value:(uint32_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(BOOL key, uint32_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBBoolUInt32Dictionary *)otherDictionary; + +- (void)setValue:(uint32_t)value forKey:(BOOL)key; + +- (void)removeValueForKey:(BOOL)aKey; +- (void)removeAll; + +@end + +#pragma mark - Bool -> Int32 + +@interface GPBBoolInt32Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(int32_t)value + forKey:(BOOL)key; ++ (instancetype)dictionaryWithValues:(const int32_t [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBBoolInt32Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBBoolInt32Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(BOOL)key value:(int32_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(BOOL key, int32_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBBoolInt32Dictionary *)otherDictionary; + +- (void)setValue:(int32_t)value forKey:(BOOL)key; + +- (void)removeValueForKey:(BOOL)aKey; +- (void)removeAll; + +@end + +#pragma mark - Bool -> UInt64 + +@interface GPBBoolUInt64Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(uint64_t)value + forKey:(BOOL)key; ++ (instancetype)dictionaryWithValues:(const uint64_t [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBBoolUInt64Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const uint64_t [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBBoolUInt64Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(BOOL)key value:(uint64_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(BOOL key, uint64_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBBoolUInt64Dictionary *)otherDictionary; + +- (void)setValue:(uint64_t)value forKey:(BOOL)key; + +- (void)removeValueForKey:(BOOL)aKey; +- (void)removeAll; + +@end + +#pragma mark - Bool -> Int64 + +@interface GPBBoolInt64Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(int64_t)value + forKey:(BOOL)key; ++ (instancetype)dictionaryWithValues:(const int64_t [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBBoolInt64Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const int64_t [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBBoolInt64Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(BOOL)key value:(int64_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(BOOL key, int64_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBBoolInt64Dictionary *)otherDictionary; + +- (void)setValue:(int64_t)value forKey:(BOOL)key; + +- (void)removeValueForKey:(BOOL)aKey; +- (void)removeAll; + +@end + +#pragma mark - Bool -> Bool + +@interface GPBBoolBoolDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(BOOL)value + forKey:(BOOL)key; ++ (instancetype)dictionaryWithValues:(const BOOL [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBBoolBoolDictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const BOOL [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBBoolBoolDictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(BOOL)key value:(BOOL *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(BOOL key, BOOL value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBBoolBoolDictionary *)otherDictionary; + +- (void)setValue:(BOOL)value forKey:(BOOL)key; + +- (void)removeValueForKey:(BOOL)aKey; +- (void)removeAll; + +@end + +#pragma mark - Bool -> Float + +@interface GPBBoolFloatDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(float)value + forKey:(BOOL)key; ++ (instancetype)dictionaryWithValues:(const float [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBBoolFloatDictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const float [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBBoolFloatDictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(BOOL)key value:(float *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(BOOL key, float value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBBoolFloatDictionary *)otherDictionary; + +- (void)setValue:(float)value forKey:(BOOL)key; + +- (void)removeValueForKey:(BOOL)aKey; +- (void)removeAll; + +@end + +#pragma mark - Bool -> Double + +@interface GPBBoolDoubleDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(double)value + forKey:(BOOL)key; ++ (instancetype)dictionaryWithValues:(const double [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBBoolDoubleDictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const double [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBBoolDoubleDictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(BOOL)key value:(double *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(BOOL key, double value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBBoolDoubleDictionary *)otherDictionary; + +- (void)setValue:(double)value forKey:(BOOL)key; + +- (void)removeValueForKey:(BOOL)aKey; +- (void)removeAll; + +@end + +#pragma mark - Bool -> Enum + +@interface GPBBoolEnumDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; +@property(nonatomic, readonly) GPBEnumValidationFunc validationFunc; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValue:(int32_t)rawValue + forKey:(BOOL)key; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBBoolEnumDictionary *)dictionary; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems; + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func; +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBBoolEnumDictionary *)dictionary; +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems; + +// These will return kGPBUnrecognizedEnumeratorValue if the value for the key +// is not a valid enumerator as defined by validationFunc. If the actual value is +// desired, use "raw" version of the method. + +- (BOOL)valueForKey:(BOOL)key value:(int32_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(BOOL key, int32_t value, BOOL *stop))block; + +// These methods bypass the validationFunc to provide access to values that were not +// known at the time the binary was compiled. + +- (BOOL)valueForKey:(BOOL)key rawValue:(int32_t *)rawValue; + +- (void)enumerateKeysAndRawValuesUsingBlock: + (void (^)(BOOL key, int32_t rawValue, BOOL *stop))block; + +- (void)addRawEntriesFromDictionary:(GPBBoolEnumDictionary *)otherDictionary; + +// If value is not a valid enumerator as defined by validationFunc, these +// methods will assert in debug, and will log in release and assign the value +// to the default value. Use the rawValue methods below to assign non enumerator +// values. + +- (void)setValue:(int32_t)value forKey:(BOOL)key; + +// This method bypass the validationFunc to provide setting of values that were not +// known at the time the binary was compiled. +- (void)setRawValue:(int32_t)rawValue forKey:(BOOL)key; + +// No validation applies to these methods. + +- (void)removeValueForKey:(BOOL)aKey; +- (void)removeAll; + +@end + +#pragma mark - Bool -> Object + +@interface GPBBoolObjectDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(id)value + forKey:(BOOL)key; ++ (instancetype)dictionaryWithValues:(const id GPB_UNSAFE_UNRETAINED [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBBoolObjectDictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const id GPB_UNSAFE_UNRETAINED [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBBoolObjectDictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (id)valueForKey:(BOOL)key; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(BOOL key, id value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBBoolObjectDictionary *)otherDictionary; + +- (void)setValue:(id)value forKey:(BOOL)key; + +- (void)removeValueForKey:(BOOL)aKey; +- (void)removeAll; + +@end + +#pragma mark - String -> UInt32 + +@interface GPBStringUInt32Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(uint32_t)value + forKey:(NSString *)key; ++ (instancetype)dictionaryWithValues:(const uint32_t [])values + forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBStringUInt32Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const uint32_t [])values + forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBStringUInt32Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(NSString *)key value:(uint32_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(NSString *key, uint32_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBStringUInt32Dictionary *)otherDictionary; + +- (void)setValue:(uint32_t)value forKey:(NSString *)key; + +- (void)removeValueForKey:(NSString *)aKey; +- (void)removeAll; + +@end + +#pragma mark - String -> Int32 + +@interface GPBStringInt32Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(int32_t)value + forKey:(NSString *)key; ++ (instancetype)dictionaryWithValues:(const int32_t [])values + forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBStringInt32Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBStringInt32Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(NSString *)key value:(int32_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(NSString *key, int32_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBStringInt32Dictionary *)otherDictionary; + +- (void)setValue:(int32_t)value forKey:(NSString *)key; + +- (void)removeValueForKey:(NSString *)aKey; +- (void)removeAll; + +@end + +#pragma mark - String -> UInt64 + +@interface GPBStringUInt64Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(uint64_t)value + forKey:(NSString *)key; ++ (instancetype)dictionaryWithValues:(const uint64_t [])values + forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBStringUInt64Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const uint64_t [])values + forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBStringUInt64Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(NSString *)key value:(uint64_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(NSString *key, uint64_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBStringUInt64Dictionary *)otherDictionary; + +- (void)setValue:(uint64_t)value forKey:(NSString *)key; + +- (void)removeValueForKey:(NSString *)aKey; +- (void)removeAll; + +@end + +#pragma mark - String -> Int64 + +@interface GPBStringInt64Dictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(int64_t)value + forKey:(NSString *)key; ++ (instancetype)dictionaryWithValues:(const int64_t [])values + forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBStringInt64Dictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const int64_t [])values + forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBStringInt64Dictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(NSString *)key value:(int64_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(NSString *key, int64_t value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBStringInt64Dictionary *)otherDictionary; + +- (void)setValue:(int64_t)value forKey:(NSString *)key; + +- (void)removeValueForKey:(NSString *)aKey; +- (void)removeAll; + +@end + +#pragma mark - String -> Bool + +@interface GPBStringBoolDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(BOOL)value + forKey:(NSString *)key; ++ (instancetype)dictionaryWithValues:(const BOOL [])values + forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBStringBoolDictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const BOOL [])values + forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBStringBoolDictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(NSString *)key value:(BOOL *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(NSString *key, BOOL value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBStringBoolDictionary *)otherDictionary; + +- (void)setValue:(BOOL)value forKey:(NSString *)key; + +- (void)removeValueForKey:(NSString *)aKey; +- (void)removeAll; + +@end + +#pragma mark - String -> Float + +@interface GPBStringFloatDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(float)value + forKey:(NSString *)key; ++ (instancetype)dictionaryWithValues:(const float [])values + forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBStringFloatDictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const float [])values + forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBStringFloatDictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(NSString *)key value:(float *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(NSString *key, float value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBStringFloatDictionary *)otherDictionary; + +- (void)setValue:(float)value forKey:(NSString *)key; + +- (void)removeValueForKey:(NSString *)aKey; +- (void)removeAll; + +@end + +#pragma mark - String -> Double + +@interface GPBStringDoubleDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValue:(double)value + forKey:(NSString *)key; ++ (instancetype)dictionaryWithValues:(const double [])values + forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBStringDoubleDictionary *)dictionary; ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; + +- (instancetype)initWithValues:(const double [])values + forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBStringDoubleDictionary *)dictionary; +- (instancetype)initWithCapacity:(NSUInteger)numItems; + +- (BOOL)valueForKey:(NSString *)key value:(double *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(NSString *key, double value, BOOL *stop))block; + +- (void)addEntriesFromDictionary:(GPBStringDoubleDictionary *)otherDictionary; + +- (void)setValue:(double)value forKey:(NSString *)key; + +- (void)removeValueForKey:(NSString *)aKey; +- (void)removeAll; + +@end + +#pragma mark - String -> Enum + +@interface GPBStringEnumDictionary : NSObject <NSCopying> + +@property(nonatomic, readonly) NSUInteger count; +@property(nonatomic, readonly) GPBEnumValidationFunc validationFunc; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValue:(int32_t)rawValue + forKey:(NSString *)key; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])values + forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys + count:(NSUInteger)count; ++ (instancetype)dictionaryWithDictionary:(GPBStringEnumDictionary *)dictionary; ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems; + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func; +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])values + forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys + count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDictionary:(GPBStringEnumDictionary *)dictionary; +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems; + +// These will return kGPBUnrecognizedEnumeratorValue if the value for the key +// is not a valid enumerator as defined by validationFunc. If the actual value is +// desired, use "raw" version of the method. + +- (BOOL)valueForKey:(NSString *)key value:(int32_t *)value; + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(NSString *key, int32_t value, BOOL *stop))block; + +// These methods bypass the validationFunc to provide access to values that were not +// known at the time the binary was compiled. + +- (BOOL)valueForKey:(NSString *)key rawValue:(int32_t *)rawValue; + +- (void)enumerateKeysAndRawValuesUsingBlock: + (void (^)(NSString *key, int32_t rawValue, BOOL *stop))block; + +- (void)addRawEntriesFromDictionary:(GPBStringEnumDictionary *)otherDictionary; + +// If value is not a valid enumerator as defined by validationFunc, these +// methods will assert in debug, and will log in release and assign the value +// to the default value. Use the rawValue methods below to assign non enumerator +// values. + +- (void)setValue:(int32_t)value forKey:(NSString *)key; + +// This method bypass the validationFunc to provide setting of values that were not +// known at the time the binary was compiled. +- (void)setRawValue:(int32_t)rawValue forKey:(NSString *)key; + +// No validation applies to these methods. + +- (void)removeValueForKey:(NSString *)aKey; +- (void)removeAll; + +@end + +//%PDDM-EXPAND-END DECLARE_DICTIONARIES() + +//%PDDM-DEFINE DECLARE_DICTIONARIES() +//%DICTIONARY_INTERFACES_FOR_POD_KEY(UInt32, uint32_t) +//%DICTIONARY_INTERFACES_FOR_POD_KEY(Int32, int32_t) +//%DICTIONARY_INTERFACES_FOR_POD_KEY(UInt64, uint64_t) +//%DICTIONARY_INTERFACES_FOR_POD_KEY(Int64, int64_t) +//%DICTIONARY_INTERFACES_FOR_POD_KEY(Bool, BOOL) +//%DICTIONARY_POD_INTERFACES_FOR_KEY(String, NSString, *, OBJECT) +//%PDDM-DEFINE DICTIONARY_INTERFACES_FOR_POD_KEY(KEY_NAME, KEY_TYPE) +//%DICTIONARY_POD_INTERFACES_FOR_KEY(KEY_NAME, KEY_TYPE, , POD) +//%DICTIONARY_POD_KEY_TO_OBJECT_INTERFACE(KEY_NAME, KEY_TYPE, Object, id) +//%PDDM-DEFINE DICTIONARY_POD_INTERFACES_FOR_KEY(KEY_NAME, KEY_TYPE, KisP, KHELPER) +//%DICTIONARY_KEY_TO_POD_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, UInt32, uint32_t) +//%DICTIONARY_KEY_TO_POD_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, Int32, int32_t) +//%DICTIONARY_KEY_TO_POD_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, UInt64, uint64_t) +//%DICTIONARY_KEY_TO_POD_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, Int64, int64_t) +//%DICTIONARY_KEY_TO_POD_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, Bool, BOOL) +//%DICTIONARY_KEY_TO_POD_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, Float, float) +//%DICTIONARY_KEY_TO_POD_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, Double, double) +//%DICTIONARY_KEY_TO_ENUM_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, Enum, int32_t) +//%PDDM-DEFINE DICTIONARY_KEY_TO_POD_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, VALUE_NAME, VALUE_TYPE) +//%DICTIONARY_COMMON_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, VALUE_NAME, VALUE_TYPE, POD) +//%PDDM-DEFINE DICTIONARY_POD_KEY_TO_OBJECT_INTERFACE(KEY_NAME, KEY_TYPE, VALUE_NAME, VALUE_TYPE) +//%DICTIONARY_COMMON_INTERFACE(KEY_NAME, KEY_TYPE, , POD, VALUE_NAME, VALUE_TYPE, OBJECT) +//%PDDM-DEFINE VALUE_FOR_KEY_POD(KEY_TYPE, VALUE_TYPE) +//%- (BOOL)valueForKey:(KEY_TYPE)key value:(VALUE_TYPE *)value; +//%PDDM-DEFINE VALUE_FOR_KEY_OBJECT(KEY_TYPE, VALUE_TYPE) +//%- (VALUE_TYPE)valueForKey:(KEY_TYPE)key; +//%PDDM-DEFINE VALUE_FOR_KEY_Enum(KEY_TYPE, VALUE_TYPE) +//%VALUE_FOR_KEY_POD(KEY_TYPE, VALUE_TYPE) +//%PDDM-DEFINE ARRAY_ARG_MODIFIERPOD() +// Nothing +//%PDDM-DEFINE ARRAY_ARG_MODIFIEREnum() +// Nothing +//%PDDM-DEFINE ARRAY_ARG_MODIFIEROBJECT() +//%GPB_UNSAFE_UNRETAINED ## +//%PDDM-DEFINE DICTIONARY_COMMON_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, VALUE_NAME, VALUE_TYPE, VHELPER) +//%#pragma mark - KEY_NAME -> VALUE_NAME +//% +//%@interface GPB##KEY_NAME##VALUE_NAME##Dictionary : NSObject <NSCopying> +//% +//%@property(nonatomic, readonly) NSUInteger count; +//% +//%+ (instancetype)dictionary; +//%+ (instancetype)dictionaryWithValue:(VALUE_TYPE)value +//% forKey:(KEY_TYPE##KisP$S##KisP)key; +//%+ (instancetype)dictionaryWithValues:(const VALUE_TYPE ARRAY_ARG_MODIFIER##VHELPER()[])values +//% forKeys:(const KEY_TYPE##KisP$S##KisP ARRAY_ARG_MODIFIER##KHELPER()[])keys +//% count:(NSUInteger)count; +//%+ (instancetype)dictionaryWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary; +//%+ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems; +//% +//%- (instancetype)initWithValues:(const VALUE_TYPE ARRAY_ARG_MODIFIER##VHELPER()[])values +//% forKeys:(const KEY_TYPE##KisP$S##KisP ARRAY_ARG_MODIFIER##KHELPER()[])keys +//% count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +//%- (instancetype)initWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary; +//%- (instancetype)initWithCapacity:(NSUInteger)numItems; +//% +//%DICTIONARY_IMMUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER) +//% +//%- (void)addEntriesFromDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)otherDictionary; +//% +//%DICTIONARY_MUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER) +//% +//%@end +//% + +//%PDDM-DEFINE DICTIONARY_KEY_TO_ENUM_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, VALUE_NAME, VALUE_TYPE) +//%DICTIONARY_KEY_TO_ENUM_INTERFACE2(KEY_NAME, KEY_TYPE, KisP, KHELPER, VALUE_NAME, VALUE_TYPE, Enum) +//%PDDM-DEFINE DICTIONARY_KEY_TO_ENUM_INTERFACE2(KEY_NAME, KEY_TYPE, KisP, KHELPER, VALUE_NAME, VALUE_TYPE, VHELPER) +//%#pragma mark - KEY_NAME -> VALUE_NAME +//% +//%@interface GPB##KEY_NAME##VALUE_NAME##Dictionary : NSObject <NSCopying> +//% +//%@property(nonatomic, readonly) NSUInteger count; +//%@property(nonatomic, readonly) GPBEnumValidationFunc validationFunc; +//% +//%+ (instancetype)dictionary; +//%+ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func; +//%+ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func +//% rawValue:(VALUE_TYPE)rawValue +//% forKey:(KEY_TYPE##KisP$S##KisP)key; +//%+ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func +//% rawValues:(const VALUE_TYPE ARRAY_ARG_MODIFIER##VHELPER()[])values +//% forKeys:(const KEY_TYPE##KisP$S##KisP ARRAY_ARG_MODIFIER##KHELPER()[])keys +//% count:(NSUInteger)count; +//%+ (instancetype)dictionaryWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary; +//%+ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func +//% capacity:(NSUInteger)numItems; +//% +//%- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func; +//%- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func +//% rawValues:(const VALUE_TYPE ARRAY_ARG_MODIFIER##VHELPER()[])values +//% forKeys:(const KEY_TYPE##KisP$S##KisP ARRAY_ARG_MODIFIER##KHELPER()[])keys +//% count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +//%- (instancetype)initWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary; +//%- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func +//% capacity:(NSUInteger)numItems; +//% +//%// These will return kGPBUnrecognizedEnumeratorValue if the value for the key +//%// is not a valid enumerator as defined by validationFunc. If the actual value is +//%// desired, use "raw" version of the method. +//% +//%DICTIONARY_IMMUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER) +//% +//%// These methods bypass the validationFunc to provide access to values that were not +//%// known at the time the binary was compiled. +//% +//%- (BOOL)valueForKey:(KEY_TYPE##KisP$S##KisP)key rawValue:(VALUE_TYPE *)rawValue; +//% +//%- (void)enumerateKeysAndRawValuesUsingBlock: +//% (void (^)(KEY_TYPE KisP##key, VALUE_TYPE rawValue, BOOL *stop))block; +//% +//%- (void)addRawEntriesFromDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)otherDictionary; +//% +//%// If value is not a valid enumerator as defined by validationFunc, these +//%// methods will assert in debug, and will log in release and assign the value +//%// to the default value. Use the rawValue methods below to assign non enumerator +//%// values. +//% +//%DICTIONARY_MUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER) +//% +//%@end +//% + +//%PDDM-DEFINE DICTIONARY_IMMUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER) +//%VALUE_FOR_KEY_##VHELPER(KEY_TYPE##KisP$S##KisP, VALUE_TYPE) +//% +//%- (void)enumerateKeysAndValuesUsingBlock: +//% (void (^)(KEY_TYPE KisP##key, VALUE_TYPE value, BOOL *stop))block; + +//%PDDM-DEFINE DICTIONARY_MUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER) +//%- (void)setValue:(VALUE_TYPE)value forKey:(KEY_TYPE##KisP$S##KisP)key; +//%DICTIONARY_EXTRA_MUTABLE_METHODS_##VHELPER(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE) +//%- (void)removeValueForKey:(KEY_TYPE##KisP$S##KisP)aKey; +//%- (void)removeAll; + +//%PDDM-DEFINE DICTIONARY_EXTRA_MUTABLE_METHODS_POD(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE) +// Empty +//%PDDM-DEFINE DICTIONARY_EXTRA_MUTABLE_METHODS_OBJECT(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE) +// Empty +//%PDDM-DEFINE DICTIONARY_EXTRA_MUTABLE_METHODS_Enum(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE) +//% +//%// This method bypass the validationFunc to provide setting of values that were not +//%// known at the time the binary was compiled. +//%- (void)setRawValue:(VALUE_TYPE)rawValue forKey:(KEY_TYPE##KisP$S##KisP)key; +//% +//%// No validation applies to these methods. +//% diff --git a/objectivec/GPBDictionary.m b/objectivec/GPBDictionary.m new file mode 100644 index 00000000..de7347e8 --- /dev/null +++ b/objectivec/GPBDictionary.m @@ -0,0 +1,12627 @@ +// 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. + +#import "GPBDictionary_PackagePrivate.h" + +#import "GPBCodedInputStream_PackagePrivate.h" +#import "GPBCodedOutputStream.h" +#import "GPBDescriptor_PackagePrivate.h" +#import "GPBMessage_PackagePrivate.h" +#import "GPBUtilities_PackagePrivate.h" + +// ------------------------------ NOTE ------------------------------ +// At the moment, this is all using NSNumbers in NSDictionaries under +// the hood, but it is all hidden so we can come back and optimize +// with direct CFDictionary usage later. The reason that wasn't +// done yet is needing to support 32bit iOS builds. Otherwise +// it would be pretty simple to store all this data in CFDictionaries +// directly. +// ------------------------------------------------------------------ + +#define kMapKeyFieldNumber 1 +#define kMapValueFieldNumber 2 + +static BOOL DictDefault_IsValidValue(int32_t value) { + // Anything but the bad value marker is allowed. + return (value != kGPBUnrecognizedEnumeratorValue); +} + +//%PDDM-DEFINE SERIALIZE_SUPPORT_2_TYPE(VALUE_NAME, VALUE_TYPE, GPBTYPE_NAME1, GPBTYPE_NAME2) +//%GPB_INLINE size_t ComputeDict##VALUE_NAME##FieldSize(VALUE_TYPE value, uint32_t fieldNum, GPBType wireType) { +//% NSCAssert((wireType == GPBType##GPBTYPE_NAME1) || (wireType == GPBType##GPBTYPE_NAME2), +//% @"bad type: %d", wireType); +//% if (wireType == GPBType##GPBTYPE_NAME1) { +//% return GPBCompute##GPBTYPE_NAME1##Size(fieldNum, value); +//% } else { // wireType == GPBType##GPBTYPE_NAME2 +//% return GPBCompute##GPBTYPE_NAME2##Size(fieldNum, value); +//% } +//%} +//% +//%GPB_INLINE void WriteDict##VALUE_NAME##Field(GPBCodedOutputStream *stream, VALUE_TYPE value, uint32_t fieldNum, GPBType wireType) { +//% NSCAssert((wireType == GPBType##GPBTYPE_NAME1) || (wireType == GPBType##GPBTYPE_NAME2), +//% @"bad type: %d", wireType); +//% if (wireType == GPBType##GPBTYPE_NAME1) { +//% [stream write##GPBTYPE_NAME1##:fieldNum value:value]; +//% } else { // wireType == GPBType##GPBTYPE_NAME2 +//% [stream write##GPBTYPE_NAME2##:fieldNum value:value]; +//% } +//%} +//% +//%PDDM-DEFINE SERIALIZE_SUPPORT_3_TYPE(VALUE_NAME, VALUE_TYPE, GPBTYPE_NAME1, GPBTYPE_NAME2, GPBTYPE_NAME3) +//%GPB_INLINE size_t ComputeDict##VALUE_NAME##FieldSize(VALUE_TYPE value, uint32_t fieldNum, GPBType wireType) { +//% NSCAssert((wireType == GPBType##GPBTYPE_NAME1) || (wireType == GPBType##GPBTYPE_NAME2) || (wireType == GPBType##GPBTYPE_NAME3), +//% @"bad type: %d", wireType); +//% if (wireType == GPBType##GPBTYPE_NAME1) { +//% return GPBCompute##GPBTYPE_NAME1##Size(fieldNum, value); +//% } else if (wireType == GPBType##GPBTYPE_NAME2) { +//% return GPBCompute##GPBTYPE_NAME2##Size(fieldNum, value); +//% } else { // wireType == GPBType##GPBTYPE_NAME3 +//% return GPBCompute##GPBTYPE_NAME3##Size(fieldNum, value); +//% } +//%} +//% +//%GPB_INLINE void WriteDict##VALUE_NAME##Field(GPBCodedOutputStream *stream, VALUE_TYPE value, uint32_t fieldNum, GPBType wireType) { +//% NSCAssert((wireType == GPBType##GPBTYPE_NAME1) || (wireType == GPBType##GPBTYPE_NAME2) || (wireType == GPBType##GPBTYPE_NAME3), +//% @"bad type: %d", wireType); +//% if (wireType == GPBType##GPBTYPE_NAME1) { +//% [stream write##GPBTYPE_NAME1##:fieldNum value:value]; +//% } else if (wireType == GPBType##GPBTYPE_NAME2) { +//% [stream write##GPBTYPE_NAME2##:fieldNum value:value]; +//% } else { // wireType == GPBType##GPBTYPE_NAME3 +//% [stream write##GPBTYPE_NAME3##:fieldNum value:value]; +//% } +//%} +//% +//%PDDM-DEFINE SIMPLE_SERIALIZE_SUPPORT(VALUE_NAME, VALUE_TYPE, VisP) +//%GPB_INLINE size_t ComputeDict##VALUE_NAME##FieldSize(VALUE_TYPE VisP##value, uint32_t fieldNum, GPBType wireType) { +//% NSCAssert(wireType == GPBType##VALUE_NAME, @"bad type: %d", wireType); +//% return GPBCompute##VALUE_NAME##Size(fieldNum, value); +//%} +//% +//%GPB_INLINE void WriteDict##VALUE_NAME##Field(GPBCodedOutputStream *stream, VALUE_TYPE VisP##value, uint32_t fieldNum, GPBType wireType) { +//% NSCAssert(wireType == GPBType##VALUE_NAME, @"bad type: %d", wireType); +//% [stream write##VALUE_NAME##:fieldNum value:value]; +//%} +//% +//%PDDM-DEFINE SERIALIZE_SUPPORT_HELPERS() +//%SERIALIZE_SUPPORT_3_TYPE(Int32, int32_t, Int32, SInt32, SFixed32) +//%SERIALIZE_SUPPORT_2_TYPE(UInt32, uint32_t, UInt32, Fixed32) +//%SERIALIZE_SUPPORT_3_TYPE(Int64, int64_t, Int64, SInt64, SFixed64) +//%SERIALIZE_SUPPORT_2_TYPE(UInt64, uint64_t, UInt64, Fixed64) +//%SIMPLE_SERIALIZE_SUPPORT(Bool, BOOL, ) +//%SIMPLE_SERIALIZE_SUPPORT(Enum, int32_t, ) +//%SIMPLE_SERIALIZE_SUPPORT(Float, float, ) +//%SIMPLE_SERIALIZE_SUPPORT(Double, double, ) +//%SIMPLE_SERIALIZE_SUPPORT(String, NSString, *) +//%SERIALIZE_SUPPORT_3_TYPE(Object, id, Message, String, Data) +//%PDDM-EXPAND SERIALIZE_SUPPORT_HELPERS() +// This block of code is generated, do not edit it directly. + +GPB_INLINE size_t ComputeDictInt32FieldSize(int32_t value, uint32_t fieldNum, GPBType wireType) { + NSCAssert((wireType == GPBTypeInt32) || (wireType == GPBTypeSInt32) || (wireType == GPBTypeSFixed32), + @"bad type: %d", wireType); + if (wireType == GPBTypeInt32) { + return GPBComputeInt32Size(fieldNum, value); + } else if (wireType == GPBTypeSInt32) { + return GPBComputeSInt32Size(fieldNum, value); + } else { // wireType == GPBTypeSFixed32 + return GPBComputeSFixed32Size(fieldNum, value); + } +} + +GPB_INLINE void WriteDictInt32Field(GPBCodedOutputStream *stream, int32_t value, uint32_t fieldNum, GPBType wireType) { + NSCAssert((wireType == GPBTypeInt32) || (wireType == GPBTypeSInt32) || (wireType == GPBTypeSFixed32), + @"bad type: %d", wireType); + if (wireType == GPBTypeInt32) { + [stream writeInt32:fieldNum value:value]; + } else if (wireType == GPBTypeSInt32) { + [stream writeSInt32:fieldNum value:value]; + } else { // wireType == GPBTypeSFixed32 + [stream writeSFixed32:fieldNum value:value]; + } +} + +GPB_INLINE size_t ComputeDictUInt32FieldSize(uint32_t value, uint32_t fieldNum, GPBType wireType) { + NSCAssert((wireType == GPBTypeUInt32) || (wireType == GPBTypeFixed32), + @"bad type: %d", wireType); + if (wireType == GPBTypeUInt32) { + return GPBComputeUInt32Size(fieldNum, value); + } else { // wireType == GPBTypeFixed32 + return GPBComputeFixed32Size(fieldNum, value); + } +} + +GPB_INLINE void WriteDictUInt32Field(GPBCodedOutputStream *stream, uint32_t value, uint32_t fieldNum, GPBType wireType) { + NSCAssert((wireType == GPBTypeUInt32) || (wireType == GPBTypeFixed32), + @"bad type: %d", wireType); + if (wireType == GPBTypeUInt32) { + [stream writeUInt32:fieldNum value:value]; + } else { // wireType == GPBTypeFixed32 + [stream writeFixed32:fieldNum value:value]; + } +} + +GPB_INLINE size_t ComputeDictInt64FieldSize(int64_t value, uint32_t fieldNum, GPBType wireType) { + NSCAssert((wireType == GPBTypeInt64) || (wireType == GPBTypeSInt64) || (wireType == GPBTypeSFixed64), + @"bad type: %d", wireType); + if (wireType == GPBTypeInt64) { + return GPBComputeInt64Size(fieldNum, value); + } else if (wireType == GPBTypeSInt64) { + return GPBComputeSInt64Size(fieldNum, value); + } else { // wireType == GPBTypeSFixed64 + return GPBComputeSFixed64Size(fieldNum, value); + } +} + +GPB_INLINE void WriteDictInt64Field(GPBCodedOutputStream *stream, int64_t value, uint32_t fieldNum, GPBType wireType) { + NSCAssert((wireType == GPBTypeInt64) || (wireType == GPBTypeSInt64) || (wireType == GPBTypeSFixed64), + @"bad type: %d", wireType); + if (wireType == GPBTypeInt64) { + [stream writeInt64:fieldNum value:value]; + } else if (wireType == GPBTypeSInt64) { + [stream writeSInt64:fieldNum value:value]; + } else { // wireType == GPBTypeSFixed64 + [stream writeSFixed64:fieldNum value:value]; + } +} + +GPB_INLINE size_t ComputeDictUInt64FieldSize(uint64_t value, uint32_t fieldNum, GPBType wireType) { + NSCAssert((wireType == GPBTypeUInt64) || (wireType == GPBTypeFixed64), + @"bad type: %d", wireType); + if (wireType == GPBTypeUInt64) { + return GPBComputeUInt64Size(fieldNum, value); + } else { // wireType == GPBTypeFixed64 + return GPBComputeFixed64Size(fieldNum, value); + } +} + +GPB_INLINE void WriteDictUInt64Field(GPBCodedOutputStream *stream, uint64_t value, uint32_t fieldNum, GPBType wireType) { + NSCAssert((wireType == GPBTypeUInt64) || (wireType == GPBTypeFixed64), + @"bad type: %d", wireType); + if (wireType == GPBTypeUInt64) { + [stream writeUInt64:fieldNum value:value]; + } else { // wireType == GPBTypeFixed64 + [stream writeFixed64:fieldNum value:value]; + } +} + +GPB_INLINE size_t ComputeDictBoolFieldSize(BOOL value, uint32_t fieldNum, GPBType wireType) { + NSCAssert(wireType == GPBTypeBool, @"bad type: %d", wireType); + return GPBComputeBoolSize(fieldNum, value); +} + +GPB_INLINE void WriteDictBoolField(GPBCodedOutputStream *stream, BOOL value, uint32_t fieldNum, GPBType wireType) { + NSCAssert(wireType == GPBTypeBool, @"bad type: %d", wireType); + [stream writeBool:fieldNum value:value]; +} + +GPB_INLINE size_t ComputeDictEnumFieldSize(int32_t value, uint32_t fieldNum, GPBType wireType) { + NSCAssert(wireType == GPBTypeEnum, @"bad type: %d", wireType); + return GPBComputeEnumSize(fieldNum, value); +} + +GPB_INLINE void WriteDictEnumField(GPBCodedOutputStream *stream, int32_t value, uint32_t fieldNum, GPBType wireType) { + NSCAssert(wireType == GPBTypeEnum, @"bad type: %d", wireType); + [stream writeEnum:fieldNum value:value]; +} + +GPB_INLINE size_t ComputeDictFloatFieldSize(float value, uint32_t fieldNum, GPBType wireType) { + NSCAssert(wireType == GPBTypeFloat, @"bad type: %d", wireType); + return GPBComputeFloatSize(fieldNum, value); +} + +GPB_INLINE void WriteDictFloatField(GPBCodedOutputStream *stream, float value, uint32_t fieldNum, GPBType wireType) { + NSCAssert(wireType == GPBTypeFloat, @"bad type: %d", wireType); + [stream writeFloat:fieldNum value:value]; +} + +GPB_INLINE size_t ComputeDictDoubleFieldSize(double value, uint32_t fieldNum, GPBType wireType) { + NSCAssert(wireType == GPBTypeDouble, @"bad type: %d", wireType); + return GPBComputeDoubleSize(fieldNum, value); +} + +GPB_INLINE void WriteDictDoubleField(GPBCodedOutputStream *stream, double value, uint32_t fieldNum, GPBType wireType) { + NSCAssert(wireType == GPBTypeDouble, @"bad type: %d", wireType); + [stream writeDouble:fieldNum value:value]; +} + +GPB_INLINE size_t ComputeDictStringFieldSize(NSString *value, uint32_t fieldNum, GPBType wireType) { + NSCAssert(wireType == GPBTypeString, @"bad type: %d", wireType); + return GPBComputeStringSize(fieldNum, value); +} + +GPB_INLINE void WriteDictStringField(GPBCodedOutputStream *stream, NSString *value, uint32_t fieldNum, GPBType wireType) { + NSCAssert(wireType == GPBTypeString, @"bad type: %d", wireType); + [stream writeString:fieldNum value:value]; +} + +GPB_INLINE size_t ComputeDictObjectFieldSize(id value, uint32_t fieldNum, GPBType wireType) { + NSCAssert((wireType == GPBTypeMessage) || (wireType == GPBTypeString) || (wireType == GPBTypeData), + @"bad type: %d", wireType); + if (wireType == GPBTypeMessage) { + return GPBComputeMessageSize(fieldNum, value); + } else if (wireType == GPBTypeString) { + return GPBComputeStringSize(fieldNum, value); + } else { // wireType == GPBTypeData + return GPBComputeDataSize(fieldNum, value); + } +} + +GPB_INLINE void WriteDictObjectField(GPBCodedOutputStream *stream, id value, uint32_t fieldNum, GPBType wireType) { + NSCAssert((wireType == GPBTypeMessage) || (wireType == GPBTypeString) || (wireType == GPBTypeData), + @"bad type: %d", wireType); + if (wireType == GPBTypeMessage) { + [stream writeMessage:fieldNum value:value]; + } else if (wireType == GPBTypeString) { + [stream writeString:fieldNum value:value]; + } else { // wireType == GPBTypeData + [stream writeData:fieldNum value:value]; + } +} + +//%PDDM-EXPAND-END SERIALIZE_SUPPORT_HELPERS() + +size_t GPBDictionaryComputeSizeInternalHelper(NSDictionary *dict, GPBFieldDescriptor *field) { + NSCAssert(field.mapKeyType == GPBTypeString, @"Unexpected key type"); + GPBType mapValueType = GPBGetFieldType(field); + __block size_t result = 0; + [dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) { + #pragma unused(stop) + size_t msgSize = GPBComputeStringSize(kMapKeyFieldNumber, key); + msgSize += ComputeDictObjectFieldSize(obj, kMapValueFieldNumber, mapValueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * dict.count; + return result; +} + +void GPBDictionaryWriteToStreamInternalHelper(GPBCodedOutputStream *outputStream, + NSDictionary *dict, + GPBFieldDescriptor *field) { + NSCAssert(field.mapKeyType == GPBTypeString, @"Unexpected key type"); + GPBType mapValueType = GPBGetFieldType(field); + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = GPBComputeStringSize(kMapKeyFieldNumber, key); + msgSize += ComputeDictObjectFieldSize(obj, kMapValueFieldNumber, mapValueType); + + // Write the size and fields. + [outputStream writeInt32NoTag:(int32_t)msgSize]; + [outputStream writeString:kMapValueFieldNumber value:obj]; + WriteDictObjectField(outputStream, obj, kMapValueFieldNumber, mapValueType); + }]; +} + +BOOL GPBDictionaryIsInitializedInternalHelper(NSDictionary *dict, GPBFieldDescriptor *field) { + NSCAssert(field.mapKeyType == GPBTypeString, @"Unexpected key type"); + NSCAssert(GPBGetFieldType(field) == GPBTypeMessage, @"Unexpected value type"); + for (GPBMessage *msg in [dict objectEnumerator]) { + if (!msg.initialized) { + return NO; + } + } + return YES; +} + +// Note: if the type is an object, it the retain pass back to the caller. +static void ReadValue(GPBCodedInputStream *stream, + GPBValue *valueToFill, + GPBType type, + GPBExtensionRegistry *registry, + GPBFieldDescriptor *field) { + switch (type) { + case GPBTypeBool: + valueToFill->valueBool = GPBCodedInputStreamReadBool(&stream->state_); + break; + case GPBTypeFixed32: + valueToFill->valueUInt32 = GPBCodedInputStreamReadFixed32(&stream->state_); + break; + case GPBTypeSFixed32: + valueToFill->valueInt32 = GPBCodedInputStreamReadSFixed32(&stream->state_); + break; + case GPBTypeFloat: + valueToFill->valueFloat = GPBCodedInputStreamReadFloat(&stream->state_); + break; + case GPBTypeFixed64: + valueToFill->valueUInt64 = GPBCodedInputStreamReadFixed64(&stream->state_); + break; + case GPBTypeSFixed64: + valueToFill->valueInt64 = GPBCodedInputStreamReadSFixed64(&stream->state_); + break; + case GPBTypeDouble: + valueToFill->valueDouble = GPBCodedInputStreamReadDouble(&stream->state_); + break; + case GPBTypeInt32: + valueToFill->valueInt32 = GPBCodedInputStreamReadInt32(&stream->state_); + break; + case GPBTypeInt64: + valueToFill->valueInt64 = GPBCodedInputStreamReadInt32(&stream->state_); + break; + case GPBTypeSInt32: + valueToFill->valueInt32 = GPBCodedInputStreamReadSInt32(&stream->state_); + break; + case GPBTypeSInt64: + valueToFill->valueInt64 = GPBCodedInputStreamReadSInt64(&stream->state_); + break; + case GPBTypeUInt32: + valueToFill->valueUInt32 = GPBCodedInputStreamReadUInt32(&stream->state_); + break; + case GPBTypeUInt64: + valueToFill->valueUInt64 = GPBCodedInputStreamReadUInt64(&stream->state_); + break; + case GPBTypeData: + [valueToFill->valueData release]; + valueToFill->valueData = GPBCodedInputStreamReadRetainedData(&stream->state_); + break; + case GPBTypeString: + [valueToFill->valueString release]; + valueToFill->valueString = GPBCodedInputStreamReadRetainedString(&stream->state_); + break; + case GPBTypeMessage: { + GPBMessage *message = [[field.msgClass alloc] init]; + [stream readMessage:message extensionRegistry:registry]; + [valueToFill->valueMessage release]; + valueToFill->valueMessage = message; + break; + } + case GPBTypeGroup: + NSCAssert(NO, @"Can't happen"); + break; + case GPBTypeEnum: + valueToFill->valueEnum = GPBCodedInputStreamReadEnum(&stream->state_); + break; + } +} + +void GPBDictionaryReadEntry(id mapDictionary, + GPBCodedInputStream *stream, + GPBExtensionRegistry *registry, + GPBFieldDescriptor *field, + GPBMessage *parentMessage) { + GPBType keyType = field.mapKeyType; + GPBType valueType = GPBGetFieldType(field); + + GPBValue key; + GPBValue value; + // Zero them (but pick up any enum default for proto2). + key.valueString = value.valueString = nil; + if (valueType == GPBTypeEnum) { + value = field.defaultValue; + } + + GPBCodedInputStreamState *state = &stream->state_; + uint32_t keyTag = + GPBWireFormatMakeTag(kMapKeyFieldNumber, GPBWireFormatForType(keyType, NO)); + uint32_t valueTag = + GPBWireFormatMakeTag(kMapValueFieldNumber, GPBWireFormatForType(valueType, NO)); + + BOOL hitError = NO; + while (YES) { + uint32_t tag = GPBCodedInputStreamReadTag(state); + if (tag == keyTag) { + ReadValue(stream, &key, keyType, registry, field); + } else if (tag == valueTag) { + ReadValue(stream, &value, valueType, registry, field); + } else if (tag == 0) { + // zero signals EOF / limit reached + break; + } else { // Unknown + if (![stream skipField:tag]){ + hitError = YES; + break; + } + } + } + + if (!hitError) { + // Handle the special defaults and/or missing key/value. + if ((keyType == GPBTypeString) && (key.valueString == nil)) { + key.valueString = [@"" retain]; + } + if (GPBTypeIsObject(valueType) && value.valueString == nil) { + switch (valueType) { + case GPBTypeString: + value.valueString = [@"" retain]; + break; + case GPBTypeData: + value.valueData = [GPBEmptyNSData() retain]; + break; + case GPBTypeMessage: { + value.valueMessage = [[field.msgClass alloc] init]; + break; + } + default: + // Nothing + break; + } + } + + if ((keyType == GPBTypeString) && GPBTypeIsObject(valueType)) { + // mapDictionary is an NSMutableDictionary + [mapDictionary setObject:value.valueString forKey:key.valueString]; + } else { + if (valueType == GPBTypeEnum) { + if (GPBHasPreservingUnknownEnumSemantics([parentMessage descriptor].file.syntax) || + [field isValidEnumValue:value.valueEnum]) { + [mapDictionary setGPBValue:&value forGPBValueKey:&key]; + } else { + NSData *data = [mapDictionary serializedDataForUnknownValue:value.valueEnum + forKey:&key + keyType:keyType]; + [parentMessage addUnknownMapEntry:GPBFieldNumber(field) value:data]; + } + } else { + [mapDictionary setGPBValue:&value forGPBValueKey:&key]; + } + } + } + + if (GPBTypeIsObject(keyType)) [key.valueString release]; + if (GPBTypeIsObject(valueType)) [value.valueString release]; +} + +// +// Macros for the common basic cases. +// + +//%PDDM-DEFINE DICTIONARY_IMPL_FOR_POD_KEY(KEY_NAME, KEY_TYPE) +//%DICTIONARY_POD_IMPL_FOR_KEY(KEY_NAME, KEY_TYPE, , POD) +//%DICTIONARY_POD_KEY_TO_OBJECT_IMPL(KEY_NAME, KEY_TYPE, Object, id) + +//%PDDM-DEFINE DICTIONARY_POD_IMPL_FOR_KEY(KEY_NAME, KEY_TYPE, KisP, KHELPER) +//%DICTIONARY_KEY_TO_POD_IMPL(KEY_NAME, KEY_TYPE, KisP, UInt32, uint32_t, KHELPER) +//%DICTIONARY_KEY_TO_POD_IMPL(KEY_NAME, KEY_TYPE, KisP, Int32, int32_t, KHELPER) +//%DICTIONARY_KEY_TO_POD_IMPL(KEY_NAME, KEY_TYPE, KisP, UInt64, uint64_t, KHELPER) +//%DICTIONARY_KEY_TO_POD_IMPL(KEY_NAME, KEY_TYPE, KisP, Int64, int64_t, KHELPER) +//%DICTIONARY_KEY_TO_POD_IMPL(KEY_NAME, KEY_TYPE, KisP, Bool, BOOL, KHELPER) +//%DICTIONARY_KEY_TO_POD_IMPL(KEY_NAME, KEY_TYPE, KisP, Float, float, KHELPER) +//%DICTIONARY_KEY_TO_POD_IMPL(KEY_NAME, KEY_TYPE, KisP, Double, double, KHELPER) +//%DICTIONARY_KEY_TO_ENUM_IMPL(KEY_NAME, KEY_TYPE, KisP, Enum, int32_t, KHELPER) + +//%PDDM-DEFINE DICTIONARY_KEY_TO_POD_IMPL(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER) +//%DICTIONARY_COMMON_IMPL(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, POD) + +//%PDDM-DEFINE DICTIONARY_POD_KEY_TO_OBJECT_IMPL(KEY_NAME, KEY_TYPE, VALUE_NAME, VALUE_TYPE) +//%DICTIONARY_COMMON_IMPL(KEY_NAME, KEY_TYPE, , VALUE_NAME, VALUE_TYPE, POD, OBJECT) + +//%PDDM-DEFINE DICTIONARY_COMMON_IMPL(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER) +//%#pragma mark - KEY_NAME -> VALUE_NAME +//% +//%@implementation GPB##KEY_NAME##VALUE_NAME##Dictionary { +//% @package +//% NSMutableDictionary *_dictionary; +//%} +//% +//%+ (instancetype)dictionary { +//% return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +//%} +//% +//%+ (instancetype)dictionaryWithValue:(VALUE_TYPE)value +//% forKey:(KEY_TYPE##KisP$S##KisP)key { +//% // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: +//% // on to get the type correct. +//% return [[(GPB##KEY_NAME##VALUE_NAME##Dictionary*)[self alloc] initWithValues:&value +//% KEY_NAME$S VALUE_NAME$S forKeys:&key +//% KEY_NAME$S VALUE_NAME$S count:1] autorelease]; +//%} +//% +//%+ (instancetype)dictionaryWithValues:(const VALUE_TYPE [])values +//% forKeys:(const KEY_TYPE##KisP$S##KisP [])keys +//% count:(NSUInteger)count { +//% // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: +//% // on to get the type correct. +//% return [[(GPB##KEY_NAME##VALUE_NAME##Dictionary*)[self alloc] initWithValues:values +//% KEY_NAME$S VALUE_NAME$S forKeys:keys +//% KEY_NAME$S VALUE_NAME$S count:count] autorelease]; +//%} +//% +//%+ (instancetype)dictionaryWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary { +//% // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: +//% // on to get the type correct. +//% return [[(GPB##KEY_NAME##VALUE_NAME##Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +//%} +//% +//%+ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { +//% return [[[self alloc] initWithCapacity:numItems] autorelease]; +//%} +//% +//%- (instancetype)init { +//% return [self initWithValues:NULL forKeys:NULL count:0]; +//%} +//% +//%- (instancetype)initWithValues:(const VALUE_TYPE [])values +//% forKeys:(const KEY_TYPE##KisP$S##KisP [])keys +//% count:(NSUInteger)count { +//% self = [super init]; +//% if (self) { +//% _dictionary = [[NSMutableDictionary alloc] init]; +//% if (count && values && keys) { +//% for (NSUInteger i = 0; i < count; ++i) { +//% [_dictionary setObject:WRAPPED##VHELPER(values[i]) forKey:WRAPPED##KHELPER(keys[i])]; +//% } +//% } +//% } +//% return self; +//%} +//% +//%- (instancetype)initWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary { +//% self = [self initWithValues:NULL forKeys:NULL count:0]; +//% if (self) { +//% if (dictionary) { +//% [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; +//% } +//% } +//% return self; +//%} +//% +//%- (instancetype)initWithCapacity:(NSUInteger)numItems { +//% #pragma unused(numItems) +//% return [self initWithValues:NULL forKeys:NULL count:0]; +//%} +//% +//%DICTIONARY_IMMUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, ) +//% +//%VALUE_FOR_KEY_##VHELPER(KEY_TYPE##KisP$S##KisP, VALUE_NAME, VALUE_TYPE, KHELPER) +//% +//%DICTIONARY_MUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, ) +//% +//%@end +//% + +//%PDDM-DEFINE DICTIONARY_KEY_TO_ENUM_IMPL(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER) +//%DICTIONARY_KEY_TO_ENUM_IMPL2(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, POD) +//%PDDM-DEFINE DICTIONARY_KEY_TO_ENUM_IMPL2(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER) +//%#pragma mark - KEY_NAME -> VALUE_NAME +//% +//%@implementation GPB##KEY_NAME##VALUE_NAME##Dictionary { +//% @package +//% NSMutableDictionary *_dictionary; +//% GPBEnumValidationFunc _validationFunc; +//%} +//% +//%@synthesize validationFunc = _validationFunc; +//% +//%+ (instancetype)dictionary { +//% return [[[self alloc] initWithValidationFunction:NULL +//% rawValues:NULL +//% forKeys:NULL +//% count:0] autorelease]; +//%} +//% +//%+ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func { +//% return [[[self alloc] initWithValidationFunction:func +//% rawValues:NULL +//% forKeys:NULL +//% count:0] autorelease]; +//%} +//% +//%+ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func +//% rawValue:(VALUE_TYPE)rawValue +//% forKey:(KEY_TYPE##KisP$S##KisP)key { +//% // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: +//% // on to get the type correct. +//% return [[(GPB##KEY_NAME##VALUE_NAME##Dictionary*)[self alloc] initWithValidationFunction:func +//% KEY_NAME$S VALUE_NAME$S rawValues:&rawValue +//% KEY_NAME$S VALUE_NAME$S forKeys:&key +//% KEY_NAME$S VALUE_NAME$S count:1] autorelease]; +//%} +//% +//%+ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func +//% rawValues:(const VALUE_TYPE [])rawValues +//% forKeys:(const KEY_TYPE##KisP$S##KisP [])keys +//% count:(NSUInteger)count { +//% // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: +//% // on to get the type correct. +//% return [[(GPB##KEY_NAME##VALUE_NAME##Dictionary*)[self alloc] initWithValidationFunction:func +//% KEY_NAME$S VALUE_NAME$S rawValues:rawValues +//% KEY_NAME$S VALUE_NAME$S forKeys:keys +//% KEY_NAME$S VALUE_NAME$S count:count] autorelease]; +//%} +//% +//%+ (instancetype)dictionaryWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary { +//% // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: +//% // on to get the type correct. +//% return [[(GPB##KEY_NAME##VALUE_NAME##Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +//%} +//% +//%+ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func +//% capacity:(NSUInteger)numItems { +//% return [[[self alloc] initWithValidationFunction:func capacity:numItems] autorelease]; +//%} +//% +//%- (instancetype)init { +//% return [self initWithValidationFunction:NULL rawValues:NULL forKeys:NULL count:0]; +//%} +//% +//%- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func { +//% return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0]; +//%} +//% +//%- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func +//% rawValues:(const VALUE_TYPE [])rawValues +//% forKeys:(const KEY_TYPE##KisP$S##KisP [])keys +//% count:(NSUInteger)count { +//% self = [super init]; +//% if (self) { +//% _dictionary = [[NSMutableDictionary alloc] init]; +//% _validationFunc = (func != NULL ? func : DictDefault_IsValidValue); +//% if (count && rawValues && keys) { +//% for (NSUInteger i = 0; i < count; ++i) { +//% [_dictionary setObject:WRAPPED##VHELPER(rawValues[i]) forKey:WRAPPED##KHELPER(keys[i])]; +//% } +//% } +//% } +//% return self; +//%} +//% +//%- (instancetype)initWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary { +//% self = [self initWithValidationFunction:dictionary.validationFunc +//% rawValues:NULL +//% forKeys:NULL +//% count:0]; +//% if (self) { +//% if (dictionary) { +//% [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; +//% } +//% } +//% return self; +//%} +//% +//%- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func +//% capacity:(NSUInteger)numItems { +//% #pragma unused(numItems) +//% return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0]; +//%} +//% +//%DICTIONARY_IMMUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, Raw) +//% +//%- (BOOL)valueForKey:(KEY_TYPE##KisP$S##KisP)key value:(VALUE_TYPE *)value { +//% NSNumber *wrapped = [_dictionary objectForKey:WRAPPED##KHELPER(key)]; +//% if (wrapped && value) { +//% VALUE_TYPE result = UNWRAP##VALUE_NAME(wrapped); +//% if (!_validationFunc(result)) { +//% result = kGPBUnrecognizedEnumeratorValue; +//% } +//% *value = result; +//% } +//% return (wrapped != NULL); +//%} +//% +//%- (BOOL)valueForKey:(KEY_TYPE##KisP$S##KisP)key rawValue:(VALUE_TYPE *)rawValue { +//% NSNumber *wrapped = [_dictionary objectForKey:WRAPPED##KHELPER(key)]; +//% if (wrapped && rawValue) { +//% *rawValue = UNWRAP##VALUE_NAME(wrapped); +//% } +//% return (wrapped != NULL); +//%} +//% +//%- (void)enumerateKeysAndValuesUsingBlock: +//% (void (^)(KEY_TYPE KisP##key, VALUE_TYPE value, BOOL *stop))block { +//% GPBEnumValidationFunc func = _validationFunc; +//% [_dictionary enumerateKeysAndObjectsUsingBlock:^(ENUM_TYPE##KHELPER(KEY_TYPE)##aKey, +//% ENUM_TYPE##VHELPER(VALUE_TYPE)##aValue, +//% BOOL *stop) { +//% VALUE_TYPE unwrapped = UNWRAP##VALUE_NAME(aValue); +//% if (!func(unwrapped)) { +//% unwrapped = kGPBUnrecognizedEnumeratorValue; +//% } +//% block(UNWRAP##KEY_NAME(aKey), unwrapped, stop); +//% }]; +//%} +//% +//%DICTIONARY_MUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, Raw) +//% +//%- (void)setValue:(VALUE_TYPE)value forKey:(KEY_TYPE##KisP$S##KisP)key { +//% if (!_validationFunc(value)) { +//% [NSException raise:NSInvalidArgumentException +//% format:@"GPB##KEY_NAME##VALUE_NAME##Dictionary: Attempt to set an unknown enum value (%d)", +//% value]; +//% } +//% +//% [_dictionary setObject:WRAPPED##VHELPER(value) forKey:WRAPPED##KHELPER(key)]; +//%} +//% +//%@end +//% + +//%PDDM-DEFINE DICTIONARY_IMMUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, ACCESSOR_NAME) +//%- (void)dealloc { +//% [_dictionary release]; +//% [super dealloc]; +//%} +//% +//%- (instancetype)copyWithZone:(NSZone *)zone { +//% return [[GPB##KEY_NAME##VALUE_NAME##Dictionary allocWithZone:zone] initWithDictionary:self]; +//%} +//% +//%- (BOOL)isEqual:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)other { +//% if (self == other) { +//% return YES; +//% } +//% if (![other isKindOfClass:[GPB##KEY_NAME##VALUE_NAME##Dictionary class]]) { +//% return NO; +//% } +//% return [_dictionary isEqual:other->_dictionary]; +//%} +//% +//%- (NSUInteger)hash { +//% return _dictionary.count; +//%} +//% +//%- (NSString *)description { +//% return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +//%} +//% +//%- (NSUInteger)count { +//% return _dictionary.count; +//%} +//% +//%- (void)enumerateKeysAnd##ACCESSOR_NAME##ValuesUsingBlock: +//% (void (^)(KEY_TYPE KisP##key, VALUE_TYPE value, BOOL *stop))block { +//% [_dictionary enumerateKeysAndObjectsUsingBlock:^(ENUM_TYPE##KHELPER(KEY_TYPE)##aKey, +//% ENUM_TYPE##VHELPER(VALUE_TYPE)##aValue, +//% BOOL *stop) { +//% block(UNWRAP##KEY_NAME(aKey), UNWRAP##VALUE_NAME(aValue), stop); +//% }]; +//%} +//% +//%EXTRA_METHODS_##VHELPER(KEY_NAME, VALUE_NAME)- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { +//% NSUInteger count = _dictionary.count; +//% if (count == 0) { +//% return 0; +//% } +//% +//% GPBType valueType = GPBGetFieldType(field); +//% GPBType keyType = field.mapKeyType; +//% __block size_t result = 0; +//% [_dictionary enumerateKeysAndObjectsUsingBlock:^(ENUM_TYPE##KHELPER(KEY_TYPE)##aKey, +//% ENUM_TYPE##VHELPER(VALUE_TYPE)##aValue, +//% BOOL *stop) { +//% #pragma unused(stop) +//% size_t msgSize = ComputeDict##KEY_NAME##FieldSize(UNWRAP##KEY_NAME(aKey), kMapKeyFieldNumber, keyType); +//% msgSize += ComputeDict##VALUE_NAME##FieldSize(UNWRAP##VALUE_NAME(aValue), kMapValueFieldNumber, valueType); +//% result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; +//% }]; +//% size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); +//% result += tagSize * count; +//% return result; +//%} +//% +//%- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream +//% asField:(GPBFieldDescriptor *)field { +//% GPBType valueType = GPBGetFieldType(field); +//% GPBType keyType = field.mapKeyType; +//% uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); +//% [_dictionary enumerateKeysAndObjectsUsingBlock:^(ENUM_TYPE##KHELPER(KEY_TYPE)##aKey, +//% ENUM_TYPE##VHELPER(VALUE_TYPE)##aValue, +//% BOOL *stop) { +//% #pragma unused(stop) +//% // Write the tag. +//% [outputStream writeInt32NoTag:tag]; +//% // Write the size of the message. +//% size_t msgSize = ComputeDict##KEY_NAME##FieldSize(UNWRAP##KEY_NAME(aKey), kMapKeyFieldNumber, keyType); +//% msgSize += ComputeDict##VALUE_NAME##FieldSize(UNWRAP##VALUE_NAME(aValue), kMapValueFieldNumber, valueType); +//% [outputStream writeInt32NoTag:(int32_t)msgSize]; +//% // Write the fields. +//% WriteDict##KEY_NAME##Field(outputStream, UNWRAP##KEY_NAME(aKey), kMapKeyFieldNumber, keyType); +//% WriteDict##VALUE_NAME##Field(outputStream, UNWRAP##VALUE_NAME(aValue), kMapValueFieldNumber, valueType); +//% }]; +//%} +//% +//%SERIAL_DATA_FOR_ENTRY_##VHELPER(KEY_NAME, VALUE_NAME)- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { +//% [_dictionary setObject:WRAPPED##VHELPER(value->##GPBVALUE_##VHELPER(VALUE_NAME)##) forKey:WRAPPED##KHELPER(key->value##KEY_NAME)]; +//%} +//% +//%- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { +//% [self enumerateKeysAnd##ACCESSOR_NAME##ValuesUsingBlock:^(KEY_TYPE KisP##key, VALUE_TYPE value, BOOL *stop) { +//% #pragma unused(stop) +//% block(TEXT_FORMAT_OBJ##KEY_NAME(key), TEXT_FORMAT_OBJ##VALUE_NAME(value)); +//% }]; +//%} +//%PDDM-DEFINE DICTIONARY_MUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, ACCESSOR_NAME) +//%- (void)add##ACCESSOR_NAME##EntriesFromDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)otherDictionary { +//% if (otherDictionary) { +//% [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; +//% } +//%} +//% +//%- (void)set##ACCESSOR_NAME##Value:(VALUE_TYPE)value forKey:(KEY_TYPE##KisP$S##KisP)key { +//% [_dictionary setObject:WRAPPED##VHELPER(value) forKey:WRAPPED##KHELPER(key)]; +//%} +//% +//%- (void)removeValueForKey:(KEY_TYPE##KisP$S##KisP)aKey { +//% [_dictionary removeObjectForKey:WRAPPED##KHELPER(aKey)]; +//%} +//% +//%- (void)removeAll { +//% [_dictionary removeAllObjects]; +//%} + +// +// Custom Generation for Bool keys +// + +//%PDDM-DEFINE DICTIONARY_BOOL_KEY_TO_POD_IMPL(VALUE_NAME, VALUE_TYPE) +//%DICTIONARY_BOOL_KEY_TO_VALUE_IMPL(VALUE_NAME, VALUE_TYPE, POD) +//%PDDM-DEFINE DICTIONARY_BOOL_KEY_TO_OBJECT_IMPL(VALUE_NAME, VALUE_TYPE) +//%DICTIONARY_BOOL_KEY_TO_VALUE_IMPL(VALUE_NAME, VALUE_TYPE, OBJECT) + +//%PDDM-DEFINE DICTIONARY_BOOL_KEY_TO_VALUE_IMPL(VALUE_NAME, VALUE_TYPE, HELPER) +//%#pragma mark - Bool -> VALUE_NAME +//% +//%@implementation GPBBool##VALUE_NAME##Dictionary { +//% @package +//% VALUE_TYPE _values[2]; +//%BOOL_DICT_HAS_STORAGE_##HELPER()} +//% +//%+ (instancetype)dictionary { +//% return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +//%} +//% +//%+ (instancetype)dictionaryWithValue:(VALUE_TYPE)value +//% forKey:(BOOL)key { +//% // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: +//% // on to get the type correct. +//% return [[(GPBBool##VALUE_NAME##Dictionary*)[self alloc] initWithValues:&value +//% VALUE_NAME$S forKeys:&key +//% VALUE_NAME$S count:1] autorelease]; +//%} +//% +//%+ (instancetype)dictionaryWithValues:(const VALUE_TYPE [])values +//% forKeys:(const BOOL [])keys +//% count:(NSUInteger)count { +//% // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: +//% // on to get the type correct. +//% return [[(GPBBool##VALUE_NAME##Dictionary*)[self alloc] initWithValues:values +//% VALUE_NAME$S forKeys:keys +//% VALUE_NAME$S count:count] autorelease]; +//%} +//% +//%+ (instancetype)dictionaryWithDictionary:(GPBBool##VALUE_NAME##Dictionary *)dictionary { +//% // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: +//% // on to get the type correct. +//% return [[(GPBBool##VALUE_NAME##Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +//%} +//% +//%+ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { +//% return [[[self alloc] initWithCapacity:numItems] autorelease]; +//%} +//% +//%- (instancetype)init { +//% return [self initWithValues:NULL forKeys:NULL count:0]; +//%} +//% +//%BOOL_DICT_INITS_##HELPER(VALUE_NAME, VALUE_TYPE) +//% +//%- (instancetype)initWithCapacity:(NSUInteger)numItems { +//% #pragma unused(numItems) +//% return [self initWithValues:NULL forKeys:NULL count:0]; +//%} +//% +//%BOOL_DICT_DEALLOC##HELPER()- (instancetype)copyWithZone:(NSZone *)zone { +//% return [[GPBBool##VALUE_NAME##Dictionary allocWithZone:zone] initWithDictionary:self]; +//%} +//% +//%- (BOOL)isEqual:(GPBBool##VALUE_NAME##Dictionary *)other { +//% if (self == other) { +//% return YES; +//% } +//% if (![other isKindOfClass:[GPBBool##VALUE_NAME##Dictionary class]]) { +//% return NO; +//% } +//% if ((BOOL_DICT_W_HAS##HELPER(0, ) != BOOL_DICT_W_HAS##HELPER(0, other->)) || +//% (BOOL_DICT_W_HAS##HELPER(1, ) != BOOL_DICT_W_HAS##HELPER(1, other->))) { +//% return NO; +//% } +//% if ((BOOL_DICT_W_HAS##HELPER(0, ) && (NEQ_##HELPER(_values[0], other->_values[0]))) || +//% (BOOL_DICT_W_HAS##HELPER(1, ) && (NEQ_##HELPER(_values[1], other->_values[1])))) { +//% return NO; +//% } +//% return YES; +//%} +//% +//%- (NSUInteger)hash { +//% return (BOOL_DICT_W_HAS##HELPER(0, ) ? 1 : 0) + (BOOL_DICT_W_HAS##HELPER(1, ) ? 1 : 0); +//%} +//% +//%- (NSString *)description { +//% NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> {", [self class], self]; +//% if (BOOL_DICT_W_HAS##HELPER(0, )) { +//% [result appendFormat:@"NO: STR_FORMAT_##HELPER(VALUE_NAME)", _values[0]]; +//% } +//% if (BOOL_DICT_W_HAS##HELPER(1, )) { +//% [result appendFormat:@"YES: STR_FORMAT_##HELPER(VALUE_NAME)", _values[1]]; +//% } +//% [result appendString:@" }"]; +//% return result; +//%} +//% +//%- (NSUInteger)count { +//% return (BOOL_DICT_W_HAS##HELPER(0, ) ? 1 : 0) + (BOOL_DICT_W_HAS##HELPER(1, ) ? 1 : 0); +//%} +//% +//%BOOL_VALUE_FOR_KEY_##HELPER(VALUE_TYPE) +//% +//%BOOL_SET_GPBVALUE_FOR_KEY_##HELPER(VALUE_NAME, VALUE_TYPE, VisP) +//% +//%- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { +//% if (BOOL_DICT_HAS##HELPER(0, )) { +//% block(@"false", TEXT_FORMAT_OBJ##VALUE_NAME(_values[0])); +//% } +//% if (BOOL_DICT_W_HAS##HELPER(1, )) { +//% block(@"true", TEXT_FORMAT_OBJ##VALUE_NAME(_values[1])); +//% } +//%} +//% +//%- (void)enumerateKeysAndValuesUsingBlock: +//% (void (^)(BOOL key, VALUE_TYPE value, BOOL *stop))block { +//% BOOL stop = NO; +//% if (BOOL_DICT_HAS##HELPER(0, )) { +//% block(NO, _values[0], &stop); +//% } +//% if (!stop && BOOL_DICT_W_HAS##HELPER(1, )) { +//% block(YES, _values[1], &stop); +//% } +//%} +//% +//%BOOL_EXTRA_METHODS_##HELPER(Bool, VALUE_NAME)- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { +//% GPBType valueType = GPBGetFieldType(field); +//% NSUInteger count = 0; +//% size_t result = 0; +//% for (int i = 0; i < 2; ++i) { +//% if (BOOL_DICT_HAS##HELPER(i, )) { +//% ++count; +//% size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBTypeBool); +//% msgSize += ComputeDict##VALUE_NAME##FieldSize(_values[i], kMapValueFieldNumber, valueType); +//% result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; +//% } +//% } +//% size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); +//% result += tagSize * count; +//% return result; +//%} +//% +//%- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream +//% asField:(GPBFieldDescriptor *)field { +//% GPBType valueType = GPBGetFieldType(field); +//% uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); +//% for (int i = 0; i < 2; ++i) { +//% if (BOOL_DICT_HAS##HELPER(i, )) { +//% // Write the tag. +//% [outputStream writeInt32NoTag:tag]; +//% // Write the size of the message. +//% size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBTypeBool); +//% msgSize += ComputeDict##VALUE_NAME##FieldSize(_values[i], kMapValueFieldNumber, valueType); +//% [outputStream writeInt32NoTag:(int32_t)msgSize]; +//% // Write the fields. +//% WriteDictBoolField(outputStream, (i == 1), kMapKeyFieldNumber, GPBTypeBool); +//% WriteDict##VALUE_NAME##Field(outputStream, _values[i], kMapValueFieldNumber, valueType); +//% } +//% } +//%} +//% +//%BOOL_DICT_MUTATIONS_##HELPER(VALUE_NAME, VALUE_TYPE) +//% +//%@end +//% + + +// +// Helpers for PODs +// + +//%PDDM-DEFINE VALUE_FOR_KEY_POD(KEY_TYPE, VALUE_NAME, VALUE_TYPE, KHELPER) +//%- (BOOL)valueForKey:(KEY_TYPE)key value:(VALUE_TYPE *)value { +//% NSNumber *wrapped = [_dictionary objectForKey:WRAPPED##KHELPER(key)]; +//% if (wrapped && value) { +//% *value = UNWRAP##VALUE_NAME(wrapped); +//% } +//% return (wrapped != NULL); +//%} +//%PDDM-DEFINE WRAPPEDPOD(VALUE) +//%@(VALUE) +//%PDDM-DEFINE UNWRAPUInt32(VALUE) +//%[VALUE unsignedIntValue] +//%PDDM-DEFINE UNWRAPInt32(VALUE) +//%[VALUE intValue] +//%PDDM-DEFINE UNWRAPUInt64(VALUE) +//%[VALUE unsignedLongLongValue] +//%PDDM-DEFINE UNWRAPInt64(VALUE) +//%[VALUE longLongValue] +//%PDDM-DEFINE UNWRAPBool(VALUE) +//%[VALUE boolValue] +//%PDDM-DEFINE UNWRAPFloat(VALUE) +//%[VALUE floatValue] +//%PDDM-DEFINE UNWRAPDouble(VALUE) +//%[VALUE doubleValue] +//%PDDM-DEFINE UNWRAPEnum(VALUE) +//%[VALUE intValue] +//%PDDM-DEFINE TEXT_FORMAT_OBJUInt32(VALUE) +//%[NSString stringWithFormat:@"%u", VALUE] +//%PDDM-DEFINE TEXT_FORMAT_OBJInt32(VALUE) +//%[NSString stringWithFormat:@"%d", VALUE] +//%PDDM-DEFINE TEXT_FORMAT_OBJUInt64(VALUE) +//%[NSString stringWithFormat:@"%llu", VALUE] +//%PDDM-DEFINE TEXT_FORMAT_OBJInt64(VALUE) +//%[NSString stringWithFormat:@"%lld", VALUE] +//%PDDM-DEFINE TEXT_FORMAT_OBJBool(VALUE) +//%(VALUE ? @"true" : @"false") +//%PDDM-DEFINE TEXT_FORMAT_OBJFloat(VALUE) +//%[NSString stringWithFormat:@"%.*g", FLT_DIG, VALUE] +//%PDDM-DEFINE TEXT_FORMAT_OBJDouble(VALUE) +//%[NSString stringWithFormat:@"%.*lg", DBL_DIG, VALUE] +//%PDDM-DEFINE TEXT_FORMAT_OBJEnum(VALUE) +//%@(VALUE) +//%PDDM-DEFINE ENUM_TYPEPOD(TYPE) +//%NSNumber * +//%PDDM-DEFINE NEQ_POD(VAL1, VAL2) +//%VAL1 != VAL2 +//%PDDM-DEFINE EXTRA_METHODS_POD(KEY_NAME, VALUE_NAME) +// Empty +//%PDDM-DEFINE BOOL_EXTRA_METHODS_POD(KEY_NAME, VALUE_NAME) +// Empty +//%PDDM-DEFINE SERIAL_DATA_FOR_ENTRY_POD(KEY_NAME, VALUE_NAME) +//%SERIAL_DATA_FOR_ENTRY_POD_##VALUE_NAME(KEY_NAME) +//%PDDM-DEFINE SERIAL_DATA_FOR_ENTRY_POD_UInt32(KEY_NAME) +// Empty +//%PDDM-DEFINE SERIAL_DATA_FOR_ENTRY_POD_Int32(KEY_NAME) +// Empty +//%PDDM-DEFINE SERIAL_DATA_FOR_ENTRY_POD_UInt64(KEY_NAME) +// Empty +//%PDDM-DEFINE SERIAL_DATA_FOR_ENTRY_POD_Int64(KEY_NAME) +// Empty +//%PDDM-DEFINE SERIAL_DATA_FOR_ENTRY_POD_Bool(KEY_NAME) +// Empty +//%PDDM-DEFINE SERIAL_DATA_FOR_ENTRY_POD_Float(KEY_NAME) +// Empty +//%PDDM-DEFINE SERIAL_DATA_FOR_ENTRY_POD_Double(KEY_NAME) +// Empty +//%PDDM-DEFINE SERIAL_DATA_FOR_ENTRY_POD_Enum(KEY_NAME) +//%- (NSData *)serializedDataForUnknownValue:(int32_t)value +//% forKey:(GPBValue *)key +//% keyType:(GPBType)keyType { +//% size_t msgSize = ComputeDict##KEY_NAME##FieldSize(key->value##KEY_NAME, kMapKeyFieldNumber, keyType); +//% msgSize += ComputeDictEnumFieldSize(value, kMapValueFieldNumber, GPBTypeEnum); +//% NSMutableData *data = [NSMutableData dataWithLength:msgSize]; +//% GPBCodedOutputStream *outputStream = [[GPBCodedOutputStream alloc] initWithData:data]; +//% WriteDict##KEY_NAME##Field(outputStream, key->value##KEY_NAME, kMapKeyFieldNumber, keyType); +//% WriteDictEnumField(outputStream, value, kMapValueFieldNumber, GPBTypeEnum); +//% [outputStream release]; +//% return data; +//%} +//% +//%PDDM-DEFINE GPBVALUE_POD(VALUE_NAME) +//%value##VALUE_NAME + +//%PDDM-DEFINE BOOL_DICT_HAS_STORAGE_POD() +//% BOOL _valueSet[2]; +//% +//%PDDM-DEFINE BOOL_DICT_INITS_POD(VALUE_NAME, VALUE_TYPE) +//%- (instancetype)initWithValues:(const VALUE_TYPE [])values +//% forKeys:(const BOOL [])keys +//% count:(NSUInteger)count { +//% self = [super init]; +//% if (self) { +//% for (NSUInteger i = 0; i < count; ++i) { +//% int idx = keys[i] ? 1 : 0; +//% _values[idx] = values[i]; +//% _valueSet[idx] = YES; +//% } +//% } +//% return self; +//%} +//% +//%- (instancetype)initWithDictionary:(GPBBool##VALUE_NAME##Dictionary *)dictionary { +//% self = [self initWithValues:NULL forKeys:NULL count:0]; +//% if (self) { +//% if (dictionary) { +//% for (int i = 0; i < 2; ++i) { +//% if (dictionary->_valueSet[i]) { +//% _values[i] = dictionary->_values[i]; +//% _valueSet[i] = YES; +//% } +//% } +//% } +//% } +//% return self; +//%} +//%PDDM-DEFINE BOOL_DICT_DEALLOCPOD() +// Empty +//%PDDM-DEFINE BOOL_DICT_W_HASPOD(IDX, REF) +//%BOOL_DICT_HASPOD(IDX, REF) +//%PDDM-DEFINE BOOL_DICT_HASPOD(IDX, REF) +//%REF##_valueSet[IDX] +//%PDDM-DEFINE BOOL_VALUE_FOR_KEY_POD(VALUE_TYPE) +//%- (BOOL)valueForKey:(BOOL)key value:(VALUE_TYPE *)value { +//% int idx = (key ? 1 : 0); +//% if (_valueSet[idx]) { +//% if (value) { +//% *value = _values[idx]; +//% } +//% return YES; +//% } +//% return NO; +//%} +//%PDDM-DEFINE BOOL_SET_GPBVALUE_FOR_KEY_POD(VALUE_NAME, VALUE_TYPE, VisP) +//%- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { +//% int idx = (key->valueBool ? 1 : 0); +//% _values[idx] = value->value##VALUE_NAME; +//% _valueSet[idx] = YES; +//%} +//%PDDM-DEFINE BOOL_DICT_MUTATIONS_POD(VALUE_NAME, VALUE_TYPE) +//%- (void)addEntriesFromDictionary:(GPBBool##VALUE_NAME##Dictionary *)otherDictionary { +//% if (otherDictionary) { +//% for (int i = 0; i < 2; ++i) { +//% if (otherDictionary->_valueSet[i]) { +//% _valueSet[i] = YES; +//% _values[i] = otherDictionary->_values[i]; +//% } +//% } +//% } +//%} +//% +//%- (void)setValue:(VALUE_TYPE)value forKey:(BOOL)key { +//% int idx = (key ? 1 : 0); +//% _values[idx] = value; +//% _valueSet[idx] = YES; +//%} +//% +//%- (void)removeValueForKey:(BOOL)aKey { +//% _valueSet[aKey ? 1 : 0] = NO; +//%} +//% +//%- (void)removeAll { +//% _valueSet[0] = NO; +//% _valueSet[1] = NO; +//%} +//%PDDM-DEFINE STR_FORMAT_POD(VALUE_NAME) +//%STR_FORMAT_##VALUE_NAME() +//%PDDM-DEFINE STR_FORMAT_UInt32() +//%%u +//%PDDM-DEFINE STR_FORMAT_Int32() +//%%d +//%PDDM-DEFINE STR_FORMAT_UInt64() +//%%llu +//%PDDM-DEFINE STR_FORMAT_Int64() +//%%lld +//%PDDM-DEFINE STR_FORMAT_Bool() +//%%d +//%PDDM-DEFINE STR_FORMAT_Float() +//%%f +//%PDDM-DEFINE STR_FORMAT_Double() +//%%lf + +// +// Helpers for Objects +// + +//%PDDM-DEFINE VALUE_FOR_KEY_OBJECT(KEY_TYPE, VALUE_NAME, VALUE_TYPE, KHELPER) +//%- (VALUE_TYPE)valueForKey:(KEY_TYPE)key { +//% VALUE_TYPE result = [_dictionary objectForKey:WRAPPED##KHELPER(key)]; +//% return result; +//%} +//%PDDM-DEFINE WRAPPEDOBJECT(VALUE) +//%VALUE +//%PDDM-DEFINE UNWRAPString(VALUE) +//%VALUE +//%PDDM-DEFINE UNWRAPObject(VALUE) +//%VALUE +//%PDDM-DEFINE TEXT_FORMAT_OBJString(VALUE) +//%VALUE +//%PDDM-DEFINE TEXT_FORMAT_OBJObject(VALUE) +//%VALUE +//%PDDM-DEFINE ENUM_TYPEOBJECT(TYPE) +//%ENUM_TYPEOBJECT_##TYPE() +//%PDDM-DEFINE ENUM_TYPEOBJECT_NSString() +//%NSString * +//%PDDM-DEFINE ENUM_TYPEOBJECT_id() +//%id ## +//%PDDM-DEFINE NEQ_OBJECT(VAL1, VAL2) +//%![VAL1 isEqual:VAL2] +//%PDDM-DEFINE EXTRA_METHODS_OBJECT(KEY_NAME, VALUE_NAME) +//%- (BOOL)isInitialized { +//% for (GPBMessage *msg in [_dictionary objectEnumerator]) { +//% if (!msg.initialized) { +//% return NO; +//% } +//% } +//% return YES; +//%} +//% +//%- (instancetype)deepCopyWithZone:(NSZone *)zone { +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *newDict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] init]; +//% [_dictionary enumerateKeysAndObjectsUsingBlock:^(id aKey, +//% GPBMessage *msg, +//% BOOL *stop) { +//% #pragma unused(stop) +//% GPBMessage *copiedMsg = [msg copyWithZone:zone]; +//% [newDict->_dictionary setObject:copiedMsg forKey:aKey]; +//% [copiedMsg release]; +//% }]; +//% return newDict; +//%} +//% +//% +//%PDDM-DEFINE BOOL_EXTRA_METHODS_OBJECT(KEY_NAME, VALUE_NAME) +//%- (BOOL)isInitialized { +//% if (_values[0] && ![_values[0] isInitialized]) { +//% return NO; +//% } +//% if (_values[1] && ![_values[1] isInitialized]) { +//% return NO; +//% } +//% return YES; +//%} +//% +//%- (instancetype)deepCopyWithZone:(NSZone *)zone { +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *newDict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] init]; +//% for (int i = 0; i < 2; ++i) { +//% if (_values[i] != nil) { +//% newDict->_values[i] = [_values[i] copyWithZone:zone]; +//% } +//% } +//% return newDict; +//%} +//% +//% +//%PDDM-DEFINE SERIAL_DATA_FOR_ENTRY_OBJECT(KEY_NAME, VALUE_NAME) +// Empty +//%PDDM-DEFINE GPBVALUE_OBJECT(VALUE_NAME) +//%valueString + + +//%PDDM-DEFINE BOOL_DICT_HAS_STORAGE_OBJECT() +// Empty +//%PDDM-DEFINE BOOL_DICT_INITS_OBJECT(VALUE_NAME, VALUE_TYPE) +//%- (instancetype)initWithValues:(const VALUE_TYPE [])values +//% forKeys:(const BOOL [])keys +//% count:(NSUInteger)count { +//% self = [super init]; +//% if (self) { +//% for (NSUInteger i = 0; i < count; ++i) { +//% int idx = keys[i] ? 1 : 0; +//% [_values[idx] release]; +//% _values[idx] = (VALUE_TYPE)[values[i] retain]; +//% } +//% } +//% return self; +//%} +//% +//%- (instancetype)initWithDictionary:(GPBBool##VALUE_NAME##Dictionary *)dictionary { +//% self = [self initWithValues:NULL forKeys:NULL count:0]; +//% if (self) { +//% if (dictionary) { +//% _values[0] = [dictionary->_values[0] retain]; +//% _values[1] = [dictionary->_values[1] retain]; +//% } +//% } +//% return self; +//%} +//%PDDM-DEFINE BOOL_DICT_DEALLOCOBJECT() +//%- (void)dealloc { +//% [_values[0] release]; +//% [_values[1] release]; +//% [super dealloc]; +//%} +//% +//% +//%PDDM-DEFINE BOOL_DICT_W_HASOBJECT(IDX, REF) +//%(BOOL_DICT_HASOBJECT(IDX, REF)) +//%PDDM-DEFINE BOOL_DICT_HASOBJECT(IDX, REF) +//%REF##_values[IDX] != nil +//%PDDM-DEFINE BOOL_VALUE_FOR_KEY_OBJECT(VALUE_TYPE) +//%- (VALUE_TYPE)valueForKey:(BOOL)key { +//% return _values[key ? 1 : 0]; +//%} +//%PDDM-DEFINE BOOL_SET_GPBVALUE_FOR_KEY_OBJECT(VALUE_NAME, VALUE_TYPE, VisP) +//%- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { +//% int idx = (key->valueBool ? 1 : 0); +//% [_values[idx] release]; +//% _values[idx] = [value->valueString retain]; +//%} + +//%PDDM-DEFINE BOOL_DICT_MUTATIONS_OBJECT(VALUE_NAME, VALUE_TYPE) +//%- (void)addEntriesFromDictionary:(GPBBool##VALUE_NAME##Dictionary *)otherDictionary { +//% if (otherDictionary) { +//% for (int i = 0; i < 2; ++i) { +//% if (otherDictionary->_values[i] != nil) { +//% [_values[i] release]; +//% _values[i] = [otherDictionary->_values[i] retain]; +//% } +//% } +//% } +//%} +//% +//%- (void)setValue:(VALUE_TYPE)value forKey:(BOOL)key { +//% int idx = (key ? 1 : 0); +//% [_values[idx] release]; +//% _values[idx] = [value retain]; +//%} +//% +//%- (void)removeValueForKey:(BOOL)aKey { +//% int idx = (aKey ? 1 : 0); +//% [_values[idx] release]; +//% _values[idx] = nil; +//%} +//% +//%- (void)removeAll { +//% for (int i = 0; i < 2; ++i) { +//% [_values[i] release]; +//% _values[i] = nil; +//% } +//%} +//%PDDM-DEFINE STR_FORMAT_OBJECT(VALUE_NAME) +//%%@ + + +//%PDDM-EXPAND DICTIONARY_IMPL_FOR_POD_KEY(UInt32, uint32_t) +// This block of code is generated, do not edit it directly. + +#pragma mark - UInt32 -> UInt32 + +@implementation GPBUInt32UInt32Dictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(uint32_t)value + forKey:(uint32_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32UInt32Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const uint32_t [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32UInt32Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBUInt32UInt32Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32UInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const uint32_t [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBUInt32UInt32Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBUInt32UInt32Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBUInt32UInt32Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBUInt32UInt32Dictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint32_t key, uint32_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey unsignedIntValue], [aValue unsignedIntValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictUInt32FieldSize([aValue unsignedIntValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictUInt32FieldSize([aValue unsignedIntValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictUInt32Field(outputStream, [aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + WriteDictUInt32Field(outputStream, [aValue unsignedIntValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueUInt32) forKey:@(key->valueUInt32)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(uint32_t key, uint32_t value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%u", key], [NSString stringWithFormat:@"%u", value]); + }]; +} + +- (BOOL)valueForKey:(uint32_t)key value:(uint32_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped unsignedIntValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBUInt32UInt32Dictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(uint32_t)value forKey:(uint32_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(uint32_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - UInt32 -> Int32 + +@implementation GPBUInt32Int32Dictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(int32_t)value + forKey:(uint32_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32Int32Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const int32_t [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32Int32Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBUInt32Int32Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32Int32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBUInt32Int32Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBUInt32Int32Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBUInt32Int32Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBUInt32Int32Dictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint32_t key, int32_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey unsignedIntValue], [aValue intValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictInt32FieldSize([aValue intValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictInt32FieldSize([aValue intValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictUInt32Field(outputStream, [aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + WriteDictInt32Field(outputStream, [aValue intValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueInt32) forKey:@(key->valueUInt32)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(uint32_t key, int32_t value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%u", key], [NSString stringWithFormat:@"%d", value]); + }]; +} + +- (BOOL)valueForKey:(uint32_t)key value:(int32_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped intValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBUInt32Int32Dictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(int32_t)value forKey:(uint32_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(uint32_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - UInt32 -> UInt64 + +@implementation GPBUInt32UInt64Dictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(uint64_t)value + forKey:(uint32_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32UInt64Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const uint64_t [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32UInt64Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBUInt32UInt64Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32UInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const uint64_t [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBUInt32UInt64Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBUInt32UInt64Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBUInt32UInt64Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBUInt32UInt64Dictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint32_t key, uint64_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey unsignedIntValue], [aValue unsignedLongLongValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictUInt64FieldSize([aValue unsignedLongLongValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictUInt64FieldSize([aValue unsignedLongLongValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictUInt32Field(outputStream, [aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + WriteDictUInt64Field(outputStream, [aValue unsignedLongLongValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueUInt64) forKey:@(key->valueUInt32)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(uint32_t key, uint64_t value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%u", key], [NSString stringWithFormat:@"%llu", value]); + }]; +} + +- (BOOL)valueForKey:(uint32_t)key value:(uint64_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped unsignedLongLongValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBUInt32UInt64Dictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(uint64_t)value forKey:(uint32_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(uint32_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - UInt32 -> Int64 + +@implementation GPBUInt32Int64Dictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(int64_t)value + forKey:(uint32_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32Int64Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const int64_t [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32Int64Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBUInt32Int64Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32Int64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const int64_t [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBUInt32Int64Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBUInt32Int64Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBUInt32Int64Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBUInt32Int64Dictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint32_t key, int64_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey unsignedIntValue], [aValue longLongValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictInt64FieldSize([aValue longLongValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictInt64FieldSize([aValue longLongValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictUInt32Field(outputStream, [aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + WriteDictInt64Field(outputStream, [aValue longLongValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueInt64) forKey:@(key->valueUInt32)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(uint32_t key, int64_t value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%u", key], [NSString stringWithFormat:@"%lld", value]); + }]; +} + +- (BOOL)valueForKey:(uint32_t)key value:(int64_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped longLongValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBUInt32Int64Dictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(int64_t)value forKey:(uint32_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(uint32_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - UInt32 -> Bool + +@implementation GPBUInt32BoolDictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(BOOL)value + forKey:(uint32_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32BoolDictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const BOOL [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32BoolDictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBUInt32BoolDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32BoolDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const BOOL [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBUInt32BoolDictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBUInt32BoolDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBUInt32BoolDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBUInt32BoolDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint32_t key, BOOL value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey unsignedIntValue], [aValue boolValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictBoolFieldSize([aValue boolValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictBoolFieldSize([aValue boolValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictUInt32Field(outputStream, [aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + WriteDictBoolField(outputStream, [aValue boolValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueBool) forKey:@(key->valueUInt32)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(uint32_t key, BOOL value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%u", key], (value ? @"true" : @"false")); + }]; +} + +- (BOOL)valueForKey:(uint32_t)key value:(BOOL *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped boolValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBUInt32BoolDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(BOOL)value forKey:(uint32_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(uint32_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - UInt32 -> Float + +@implementation GPBUInt32FloatDictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(float)value + forKey:(uint32_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32FloatDictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const float [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32FloatDictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBUInt32FloatDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32FloatDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const float [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBUInt32FloatDictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBUInt32FloatDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBUInt32FloatDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBUInt32FloatDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint32_t key, float value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey unsignedIntValue], [aValue floatValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictFloatFieldSize([aValue floatValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictFloatFieldSize([aValue floatValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictUInt32Field(outputStream, [aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + WriteDictFloatField(outputStream, [aValue floatValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueFloat) forKey:@(key->valueUInt32)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(uint32_t key, float value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%u", key], [NSString stringWithFormat:@"%.*g", FLT_DIG, value]); + }]; +} + +- (BOOL)valueForKey:(uint32_t)key value:(float *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped floatValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBUInt32FloatDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(float)value forKey:(uint32_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(uint32_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - UInt32 -> Double + +@implementation GPBUInt32DoubleDictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(double)value + forKey:(uint32_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32DoubleDictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const double [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32DoubleDictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBUInt32DoubleDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32DoubleDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const double [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBUInt32DoubleDictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBUInt32DoubleDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBUInt32DoubleDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBUInt32DoubleDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint32_t key, double value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey unsignedIntValue], [aValue doubleValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictDoubleFieldSize([aValue doubleValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictDoubleFieldSize([aValue doubleValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictUInt32Field(outputStream, [aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + WriteDictDoubleField(outputStream, [aValue doubleValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueDouble) forKey:@(key->valueUInt32)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(uint32_t key, double value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%u", key], [NSString stringWithFormat:@"%.*lg", DBL_DIG, value]); + }]; +} + +- (BOOL)valueForKey:(uint32_t)key value:(double *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped doubleValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBUInt32DoubleDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(double)value forKey:(uint32_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(uint32_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - UInt32 -> Enum + +@implementation GPBUInt32EnumDictionary { + @package + NSMutableDictionary *_dictionary; + GPBEnumValidationFunc _validationFunc; +} + +@synthesize validationFunc = _validationFunc; + ++ (instancetype)dictionary { + return [[[self alloc] initWithValidationFunction:NULL + rawValues:NULL + forKeys:NULL + count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func { + return [[[self alloc] initWithValidationFunction:func + rawValues:NULL + forKeys:NULL + count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValue:(int32_t)rawValue + forKey:(uint32_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32EnumDictionary*)[self alloc] initWithValidationFunction:func + rawValues:&rawValue + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])rawValues + forKeys:(const uint32_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32EnumDictionary*)[self alloc] initWithValidationFunction:func + rawValues:rawValues + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBUInt32EnumDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32EnumDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems { + return [[[self alloc] initWithValidationFunction:func capacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValidationFunction:NULL rawValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func { + return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])rawValues + forKeys:(const uint32_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + _validationFunc = (func != NULL ? func : DictDefault_IsValidValue); + if (count && rawValues && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(rawValues[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBUInt32EnumDictionary *)dictionary { + self = [self initWithValidationFunction:dictionary.validationFunc + rawValues:NULL + forKeys:NULL + count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBUInt32EnumDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBUInt32EnumDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBUInt32EnumDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndRawValuesUsingBlock: + (void (^)(uint32_t key, int32_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey unsignedIntValue], [aValue intValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictEnumFieldSize([aValue intValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictEnumFieldSize([aValue intValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictUInt32Field(outputStream, [aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + WriteDictEnumField(outputStream, [aValue intValue], kMapValueFieldNumber, valueType); + }]; +} + +- (NSData *)serializedDataForUnknownValue:(int32_t)value + forKey:(GPBValue *)key + keyType:(GPBType)keyType { + size_t msgSize = ComputeDictUInt32FieldSize(key->valueUInt32, kMapKeyFieldNumber, keyType); + msgSize += ComputeDictEnumFieldSize(value, kMapValueFieldNumber, GPBTypeEnum); + NSMutableData *data = [NSMutableData dataWithLength:msgSize]; + GPBCodedOutputStream *outputStream = [[GPBCodedOutputStream alloc] initWithData:data]; + WriteDictUInt32Field(outputStream, key->valueUInt32, kMapKeyFieldNumber, keyType); + WriteDictEnumField(outputStream, value, kMapValueFieldNumber, GPBTypeEnum); + [outputStream release]; + return data; +} +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueEnum) forKey:@(key->valueUInt32)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndRawValuesUsingBlock:^(uint32_t key, int32_t value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%u", key], @(value)); + }]; +} + +- (BOOL)valueForKey:(uint32_t)key value:(int32_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + int32_t result = [wrapped intValue]; + if (!_validationFunc(result)) { + result = kGPBUnrecognizedEnumeratorValue; + } + *value = result; + } + return (wrapped != NULL); +} + +- (BOOL)valueForKey:(uint32_t)key rawValue:(int32_t *)rawValue { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && rawValue) { + *rawValue = [wrapped intValue]; + } + return (wrapped != NULL); +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint32_t key, int32_t value, BOOL *stop))block { + GPBEnumValidationFunc func = _validationFunc; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + int32_t unwrapped = [aValue intValue]; + if (!func(unwrapped)) { + unwrapped = kGPBUnrecognizedEnumeratorValue; + } + block([aKey unsignedIntValue], unwrapped, stop); + }]; +} + +- (void)addRawEntriesFromDictionary:(GPBUInt32EnumDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setRawValue:(int32_t)value forKey:(uint32_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(uint32_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +- (void)setValue:(int32_t)value forKey:(uint32_t)key { + if (!_validationFunc(value)) { + [NSException raise:NSInvalidArgumentException + format:@"GPBUInt32EnumDictionary: Attempt to set an unknown enum value (%d)", + value]; + } + + [_dictionary setObject:@(value) forKey:@(key)]; +} + +@end + +#pragma mark - UInt32 -> Object + +@implementation GPBUInt32ObjectDictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(id)value + forKey:(uint32_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32ObjectDictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const id [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32ObjectDictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBUInt32ObjectDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt32ObjectDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const id [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:values[i] forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBUInt32ObjectDictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBUInt32ObjectDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBUInt32ObjectDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBUInt32ObjectDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint32_t key, id value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + id aValue, + BOOL *stop) { + block([aKey unsignedIntValue], aValue, stop); + }]; +} + +- (BOOL)isInitialized { + for (GPBMessage *msg in [_dictionary objectEnumerator]) { + if (!msg.initialized) { + return NO; + } + } + return YES; +} + +- (instancetype)deepCopyWithZone:(NSZone *)zone { + GPBUInt32ObjectDictionary *newDict = + [[GPBUInt32ObjectDictionary alloc] init]; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(id aKey, + GPBMessage *msg, + BOOL *stop) { + #pragma unused(stop) + GPBMessage *copiedMsg = [msg copyWithZone:zone]; + [newDict->_dictionary setObject:copiedMsg forKey:aKey]; + [copiedMsg release]; + }]; + return newDict; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + id aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictObjectFieldSize(aValue, kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + id aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictObjectFieldSize(aValue, kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictUInt32Field(outputStream, [aKey unsignedIntValue], kMapKeyFieldNumber, keyType); + WriteDictObjectField(outputStream, aValue, kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:value->valueString forKey:@(key->valueUInt32)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(uint32_t key, id value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%u", key], value); + }]; +} + +- (id)valueForKey:(uint32_t)key { + id result = [_dictionary objectForKey:@(key)]; + return result; +} + +- (void)addEntriesFromDictionary:(GPBUInt32ObjectDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(id)value forKey:(uint32_t)key { + [_dictionary setObject:value forKey:@(key)]; +} + +- (void)removeValueForKey:(uint32_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +//%PDDM-EXPAND DICTIONARY_IMPL_FOR_POD_KEY(Int32, int32_t) +// This block of code is generated, do not edit it directly. + +#pragma mark - Int32 -> UInt32 + +@implementation GPBInt32UInt32Dictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(uint32_t)value + forKey:(int32_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32UInt32Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const uint32_t [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32UInt32Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBInt32UInt32Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32UInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const uint32_t [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBInt32UInt32Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBInt32UInt32Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBInt32UInt32Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBInt32UInt32Dictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int32_t key, uint32_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey intValue], [aValue unsignedIntValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictUInt32FieldSize([aValue unsignedIntValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictUInt32FieldSize([aValue unsignedIntValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictInt32Field(outputStream, [aKey intValue], kMapKeyFieldNumber, keyType); + WriteDictUInt32Field(outputStream, [aValue unsignedIntValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueUInt32) forKey:@(key->valueInt32)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(int32_t key, uint32_t value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%d", key], [NSString stringWithFormat:@"%u", value]); + }]; +} + +- (BOOL)valueForKey:(int32_t)key value:(uint32_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped unsignedIntValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBInt32UInt32Dictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(uint32_t)value forKey:(int32_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(int32_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - Int32 -> Int32 + +@implementation GPBInt32Int32Dictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(int32_t)value + forKey:(int32_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32Int32Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const int32_t [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32Int32Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBInt32Int32Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32Int32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBInt32Int32Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBInt32Int32Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBInt32Int32Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBInt32Int32Dictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int32_t key, int32_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey intValue], [aValue intValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictInt32FieldSize([aValue intValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictInt32FieldSize([aValue intValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictInt32Field(outputStream, [aKey intValue], kMapKeyFieldNumber, keyType); + WriteDictInt32Field(outputStream, [aValue intValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueInt32) forKey:@(key->valueInt32)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(int32_t key, int32_t value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%d", key], [NSString stringWithFormat:@"%d", value]); + }]; +} + +- (BOOL)valueForKey:(int32_t)key value:(int32_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped intValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBInt32Int32Dictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(int32_t)value forKey:(int32_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(int32_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - Int32 -> UInt64 + +@implementation GPBInt32UInt64Dictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(uint64_t)value + forKey:(int32_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32UInt64Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const uint64_t [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32UInt64Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBInt32UInt64Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32UInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const uint64_t [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBInt32UInt64Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBInt32UInt64Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBInt32UInt64Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBInt32UInt64Dictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int32_t key, uint64_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey intValue], [aValue unsignedLongLongValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictUInt64FieldSize([aValue unsignedLongLongValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictUInt64FieldSize([aValue unsignedLongLongValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictInt32Field(outputStream, [aKey intValue], kMapKeyFieldNumber, keyType); + WriteDictUInt64Field(outputStream, [aValue unsignedLongLongValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueUInt64) forKey:@(key->valueInt32)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(int32_t key, uint64_t value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%d", key], [NSString stringWithFormat:@"%llu", value]); + }]; +} + +- (BOOL)valueForKey:(int32_t)key value:(uint64_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped unsignedLongLongValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBInt32UInt64Dictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(uint64_t)value forKey:(int32_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(int32_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - Int32 -> Int64 + +@implementation GPBInt32Int64Dictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(int64_t)value + forKey:(int32_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32Int64Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const int64_t [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32Int64Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBInt32Int64Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32Int64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const int64_t [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBInt32Int64Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBInt32Int64Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBInt32Int64Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBInt32Int64Dictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int32_t key, int64_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey intValue], [aValue longLongValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictInt64FieldSize([aValue longLongValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictInt64FieldSize([aValue longLongValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictInt32Field(outputStream, [aKey intValue], kMapKeyFieldNumber, keyType); + WriteDictInt64Field(outputStream, [aValue longLongValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueInt64) forKey:@(key->valueInt32)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(int32_t key, int64_t value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%d", key], [NSString stringWithFormat:@"%lld", value]); + }]; +} + +- (BOOL)valueForKey:(int32_t)key value:(int64_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped longLongValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBInt32Int64Dictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(int64_t)value forKey:(int32_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(int32_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - Int32 -> Bool + +@implementation GPBInt32BoolDictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(BOOL)value + forKey:(int32_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32BoolDictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const BOOL [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32BoolDictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBInt32BoolDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32BoolDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const BOOL [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBInt32BoolDictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBInt32BoolDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBInt32BoolDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBInt32BoolDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int32_t key, BOOL value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey intValue], [aValue boolValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictBoolFieldSize([aValue boolValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictBoolFieldSize([aValue boolValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictInt32Field(outputStream, [aKey intValue], kMapKeyFieldNumber, keyType); + WriteDictBoolField(outputStream, [aValue boolValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueBool) forKey:@(key->valueInt32)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(int32_t key, BOOL value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%d", key], (value ? @"true" : @"false")); + }]; +} + +- (BOOL)valueForKey:(int32_t)key value:(BOOL *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped boolValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBInt32BoolDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(BOOL)value forKey:(int32_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(int32_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - Int32 -> Float + +@implementation GPBInt32FloatDictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(float)value + forKey:(int32_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32FloatDictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const float [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32FloatDictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBInt32FloatDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32FloatDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const float [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBInt32FloatDictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBInt32FloatDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBInt32FloatDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBInt32FloatDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int32_t key, float value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey intValue], [aValue floatValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictFloatFieldSize([aValue floatValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictFloatFieldSize([aValue floatValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictInt32Field(outputStream, [aKey intValue], kMapKeyFieldNumber, keyType); + WriteDictFloatField(outputStream, [aValue floatValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueFloat) forKey:@(key->valueInt32)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(int32_t key, float value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%d", key], [NSString stringWithFormat:@"%.*g", FLT_DIG, value]); + }]; +} + +- (BOOL)valueForKey:(int32_t)key value:(float *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped floatValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBInt32FloatDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(float)value forKey:(int32_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(int32_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - Int32 -> Double + +@implementation GPBInt32DoubleDictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(double)value + forKey:(int32_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32DoubleDictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const double [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32DoubleDictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBInt32DoubleDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32DoubleDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const double [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBInt32DoubleDictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBInt32DoubleDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBInt32DoubleDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBInt32DoubleDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int32_t key, double value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey intValue], [aValue doubleValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictDoubleFieldSize([aValue doubleValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictDoubleFieldSize([aValue doubleValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictInt32Field(outputStream, [aKey intValue], kMapKeyFieldNumber, keyType); + WriteDictDoubleField(outputStream, [aValue doubleValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueDouble) forKey:@(key->valueInt32)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(int32_t key, double value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%d", key], [NSString stringWithFormat:@"%.*lg", DBL_DIG, value]); + }]; +} + +- (BOOL)valueForKey:(int32_t)key value:(double *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped doubleValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBInt32DoubleDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(double)value forKey:(int32_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(int32_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - Int32 -> Enum + +@implementation GPBInt32EnumDictionary { + @package + NSMutableDictionary *_dictionary; + GPBEnumValidationFunc _validationFunc; +} + +@synthesize validationFunc = _validationFunc; + ++ (instancetype)dictionary { + return [[[self alloc] initWithValidationFunction:NULL + rawValues:NULL + forKeys:NULL + count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func { + return [[[self alloc] initWithValidationFunction:func + rawValues:NULL + forKeys:NULL + count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValue:(int32_t)rawValue + forKey:(int32_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32EnumDictionary*)[self alloc] initWithValidationFunction:func + rawValues:&rawValue + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])rawValues + forKeys:(const int32_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32EnumDictionary*)[self alloc] initWithValidationFunction:func + rawValues:rawValues + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBInt32EnumDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32EnumDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems { + return [[[self alloc] initWithValidationFunction:func capacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValidationFunction:NULL rawValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func { + return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])rawValues + forKeys:(const int32_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + _validationFunc = (func != NULL ? func : DictDefault_IsValidValue); + if (count && rawValues && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(rawValues[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBInt32EnumDictionary *)dictionary { + self = [self initWithValidationFunction:dictionary.validationFunc + rawValues:NULL + forKeys:NULL + count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBInt32EnumDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBInt32EnumDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBInt32EnumDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndRawValuesUsingBlock: + (void (^)(int32_t key, int32_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey intValue], [aValue intValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictEnumFieldSize([aValue intValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictEnumFieldSize([aValue intValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictInt32Field(outputStream, [aKey intValue], kMapKeyFieldNumber, keyType); + WriteDictEnumField(outputStream, [aValue intValue], kMapValueFieldNumber, valueType); + }]; +} + +- (NSData *)serializedDataForUnknownValue:(int32_t)value + forKey:(GPBValue *)key + keyType:(GPBType)keyType { + size_t msgSize = ComputeDictInt32FieldSize(key->valueInt32, kMapKeyFieldNumber, keyType); + msgSize += ComputeDictEnumFieldSize(value, kMapValueFieldNumber, GPBTypeEnum); + NSMutableData *data = [NSMutableData dataWithLength:msgSize]; + GPBCodedOutputStream *outputStream = [[GPBCodedOutputStream alloc] initWithData:data]; + WriteDictInt32Field(outputStream, key->valueInt32, kMapKeyFieldNumber, keyType); + WriteDictEnumField(outputStream, value, kMapValueFieldNumber, GPBTypeEnum); + [outputStream release]; + return data; +} +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueEnum) forKey:@(key->valueInt32)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndRawValuesUsingBlock:^(int32_t key, int32_t value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%d", key], @(value)); + }]; +} + +- (BOOL)valueForKey:(int32_t)key value:(int32_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + int32_t result = [wrapped intValue]; + if (!_validationFunc(result)) { + result = kGPBUnrecognizedEnumeratorValue; + } + *value = result; + } + return (wrapped != NULL); +} + +- (BOOL)valueForKey:(int32_t)key rawValue:(int32_t *)rawValue { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && rawValue) { + *rawValue = [wrapped intValue]; + } + return (wrapped != NULL); +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int32_t key, int32_t value, BOOL *stop))block { + GPBEnumValidationFunc func = _validationFunc; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + int32_t unwrapped = [aValue intValue]; + if (!func(unwrapped)) { + unwrapped = kGPBUnrecognizedEnumeratorValue; + } + block([aKey intValue], unwrapped, stop); + }]; +} + +- (void)addRawEntriesFromDictionary:(GPBInt32EnumDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setRawValue:(int32_t)value forKey:(int32_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(int32_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +- (void)setValue:(int32_t)value forKey:(int32_t)key { + if (!_validationFunc(value)) { + [NSException raise:NSInvalidArgumentException + format:@"GPBInt32EnumDictionary: Attempt to set an unknown enum value (%d)", + value]; + } + + [_dictionary setObject:@(value) forKey:@(key)]; +} + +@end + +#pragma mark - Int32 -> Object + +@implementation GPBInt32ObjectDictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(id)value + forKey:(int32_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32ObjectDictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const id [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32ObjectDictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBInt32ObjectDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt32ObjectDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const id [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:values[i] forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBInt32ObjectDictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBInt32ObjectDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBInt32ObjectDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBInt32ObjectDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int32_t key, id value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + id aValue, + BOOL *stop) { + block([aKey intValue], aValue, stop); + }]; +} + +- (BOOL)isInitialized { + for (GPBMessage *msg in [_dictionary objectEnumerator]) { + if (!msg.initialized) { + return NO; + } + } + return YES; +} + +- (instancetype)deepCopyWithZone:(NSZone *)zone { + GPBInt32ObjectDictionary *newDict = + [[GPBInt32ObjectDictionary alloc] init]; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(id aKey, + GPBMessage *msg, + BOOL *stop) { + #pragma unused(stop) + GPBMessage *copiedMsg = [msg copyWithZone:zone]; + [newDict->_dictionary setObject:copiedMsg forKey:aKey]; + [copiedMsg release]; + }]; + return newDict; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + id aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictObjectFieldSize(aValue, kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + id aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictObjectFieldSize(aValue, kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictInt32Field(outputStream, [aKey intValue], kMapKeyFieldNumber, keyType); + WriteDictObjectField(outputStream, aValue, kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:value->valueString forKey:@(key->valueInt32)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(int32_t key, id value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%d", key], value); + }]; +} + +- (id)valueForKey:(int32_t)key { + id result = [_dictionary objectForKey:@(key)]; + return result; +} + +- (void)addEntriesFromDictionary:(GPBInt32ObjectDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(id)value forKey:(int32_t)key { + [_dictionary setObject:value forKey:@(key)]; +} + +- (void)removeValueForKey:(int32_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +//%PDDM-EXPAND DICTIONARY_IMPL_FOR_POD_KEY(UInt64, uint64_t) +// This block of code is generated, do not edit it directly. + +#pragma mark - UInt64 -> UInt32 + +@implementation GPBUInt64UInt32Dictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(uint32_t)value + forKey:(uint64_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64UInt32Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const uint32_t [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64UInt32Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBUInt64UInt32Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64UInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const uint32_t [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBUInt64UInt32Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBUInt64UInt32Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBUInt64UInt32Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBUInt64UInt32Dictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint64_t key, uint32_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey unsignedLongLongValue], [aValue unsignedIntValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictUInt32FieldSize([aValue unsignedIntValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictUInt32FieldSize([aValue unsignedIntValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictUInt64Field(outputStream, [aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + WriteDictUInt32Field(outputStream, [aValue unsignedIntValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueUInt32) forKey:@(key->valueUInt64)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(uint64_t key, uint32_t value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%llu", key], [NSString stringWithFormat:@"%u", value]); + }]; +} + +- (BOOL)valueForKey:(uint64_t)key value:(uint32_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped unsignedIntValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBUInt64UInt32Dictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(uint32_t)value forKey:(uint64_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(uint64_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - UInt64 -> Int32 + +@implementation GPBUInt64Int32Dictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(int32_t)value + forKey:(uint64_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64Int32Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const int32_t [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64Int32Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBUInt64Int32Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64Int32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBUInt64Int32Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBUInt64Int32Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBUInt64Int32Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBUInt64Int32Dictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint64_t key, int32_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey unsignedLongLongValue], [aValue intValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictInt32FieldSize([aValue intValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictInt32FieldSize([aValue intValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictUInt64Field(outputStream, [aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + WriteDictInt32Field(outputStream, [aValue intValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueInt32) forKey:@(key->valueUInt64)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(uint64_t key, int32_t value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%llu", key], [NSString stringWithFormat:@"%d", value]); + }]; +} + +- (BOOL)valueForKey:(uint64_t)key value:(int32_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped intValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBUInt64Int32Dictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(int32_t)value forKey:(uint64_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(uint64_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - UInt64 -> UInt64 + +@implementation GPBUInt64UInt64Dictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(uint64_t)value + forKey:(uint64_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64UInt64Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const uint64_t [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64UInt64Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBUInt64UInt64Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64UInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const uint64_t [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBUInt64UInt64Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBUInt64UInt64Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBUInt64UInt64Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBUInt64UInt64Dictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint64_t key, uint64_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey unsignedLongLongValue], [aValue unsignedLongLongValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictUInt64FieldSize([aValue unsignedLongLongValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictUInt64FieldSize([aValue unsignedLongLongValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictUInt64Field(outputStream, [aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + WriteDictUInt64Field(outputStream, [aValue unsignedLongLongValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueUInt64) forKey:@(key->valueUInt64)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(uint64_t key, uint64_t value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%llu", key], [NSString stringWithFormat:@"%llu", value]); + }]; +} + +- (BOOL)valueForKey:(uint64_t)key value:(uint64_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped unsignedLongLongValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBUInt64UInt64Dictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(uint64_t)value forKey:(uint64_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(uint64_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - UInt64 -> Int64 + +@implementation GPBUInt64Int64Dictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(int64_t)value + forKey:(uint64_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64Int64Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const int64_t [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64Int64Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBUInt64Int64Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64Int64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const int64_t [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBUInt64Int64Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBUInt64Int64Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBUInt64Int64Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBUInt64Int64Dictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint64_t key, int64_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey unsignedLongLongValue], [aValue longLongValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictInt64FieldSize([aValue longLongValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictInt64FieldSize([aValue longLongValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictUInt64Field(outputStream, [aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + WriteDictInt64Field(outputStream, [aValue longLongValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueInt64) forKey:@(key->valueUInt64)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(uint64_t key, int64_t value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%llu", key], [NSString stringWithFormat:@"%lld", value]); + }]; +} + +- (BOOL)valueForKey:(uint64_t)key value:(int64_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped longLongValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBUInt64Int64Dictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(int64_t)value forKey:(uint64_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(uint64_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - UInt64 -> Bool + +@implementation GPBUInt64BoolDictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(BOOL)value + forKey:(uint64_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64BoolDictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const BOOL [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64BoolDictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBUInt64BoolDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64BoolDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const BOOL [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBUInt64BoolDictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBUInt64BoolDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBUInt64BoolDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBUInt64BoolDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint64_t key, BOOL value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey unsignedLongLongValue], [aValue boolValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictBoolFieldSize([aValue boolValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictBoolFieldSize([aValue boolValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictUInt64Field(outputStream, [aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + WriteDictBoolField(outputStream, [aValue boolValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueBool) forKey:@(key->valueUInt64)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(uint64_t key, BOOL value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%llu", key], (value ? @"true" : @"false")); + }]; +} + +- (BOOL)valueForKey:(uint64_t)key value:(BOOL *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped boolValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBUInt64BoolDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(BOOL)value forKey:(uint64_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(uint64_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - UInt64 -> Float + +@implementation GPBUInt64FloatDictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(float)value + forKey:(uint64_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64FloatDictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const float [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64FloatDictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBUInt64FloatDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64FloatDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const float [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBUInt64FloatDictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBUInt64FloatDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBUInt64FloatDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBUInt64FloatDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint64_t key, float value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey unsignedLongLongValue], [aValue floatValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictFloatFieldSize([aValue floatValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictFloatFieldSize([aValue floatValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictUInt64Field(outputStream, [aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + WriteDictFloatField(outputStream, [aValue floatValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueFloat) forKey:@(key->valueUInt64)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(uint64_t key, float value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%llu", key], [NSString stringWithFormat:@"%.*g", FLT_DIG, value]); + }]; +} + +- (BOOL)valueForKey:(uint64_t)key value:(float *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped floatValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBUInt64FloatDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(float)value forKey:(uint64_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(uint64_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - UInt64 -> Double + +@implementation GPBUInt64DoubleDictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(double)value + forKey:(uint64_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64DoubleDictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const double [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64DoubleDictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBUInt64DoubleDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64DoubleDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const double [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBUInt64DoubleDictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBUInt64DoubleDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBUInt64DoubleDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBUInt64DoubleDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint64_t key, double value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey unsignedLongLongValue], [aValue doubleValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictDoubleFieldSize([aValue doubleValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictDoubleFieldSize([aValue doubleValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictUInt64Field(outputStream, [aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + WriteDictDoubleField(outputStream, [aValue doubleValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueDouble) forKey:@(key->valueUInt64)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(uint64_t key, double value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%llu", key], [NSString stringWithFormat:@"%.*lg", DBL_DIG, value]); + }]; +} + +- (BOOL)valueForKey:(uint64_t)key value:(double *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped doubleValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBUInt64DoubleDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(double)value forKey:(uint64_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(uint64_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - UInt64 -> Enum + +@implementation GPBUInt64EnumDictionary { + @package + NSMutableDictionary *_dictionary; + GPBEnumValidationFunc _validationFunc; +} + +@synthesize validationFunc = _validationFunc; + ++ (instancetype)dictionary { + return [[[self alloc] initWithValidationFunction:NULL + rawValues:NULL + forKeys:NULL + count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func { + return [[[self alloc] initWithValidationFunction:func + rawValues:NULL + forKeys:NULL + count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValue:(int32_t)rawValue + forKey:(uint64_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64EnumDictionary*)[self alloc] initWithValidationFunction:func + rawValues:&rawValue + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])rawValues + forKeys:(const uint64_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64EnumDictionary*)[self alloc] initWithValidationFunction:func + rawValues:rawValues + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBUInt64EnumDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64EnumDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems { + return [[[self alloc] initWithValidationFunction:func capacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValidationFunction:NULL rawValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func { + return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])rawValues + forKeys:(const uint64_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + _validationFunc = (func != NULL ? func : DictDefault_IsValidValue); + if (count && rawValues && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(rawValues[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBUInt64EnumDictionary *)dictionary { + self = [self initWithValidationFunction:dictionary.validationFunc + rawValues:NULL + forKeys:NULL + count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBUInt64EnumDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBUInt64EnumDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBUInt64EnumDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndRawValuesUsingBlock: + (void (^)(uint64_t key, int32_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey unsignedLongLongValue], [aValue intValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictEnumFieldSize([aValue intValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictEnumFieldSize([aValue intValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictUInt64Field(outputStream, [aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + WriteDictEnumField(outputStream, [aValue intValue], kMapValueFieldNumber, valueType); + }]; +} + +- (NSData *)serializedDataForUnknownValue:(int32_t)value + forKey:(GPBValue *)key + keyType:(GPBType)keyType { + size_t msgSize = ComputeDictUInt64FieldSize(key->valueUInt64, kMapKeyFieldNumber, keyType); + msgSize += ComputeDictEnumFieldSize(value, kMapValueFieldNumber, GPBTypeEnum); + NSMutableData *data = [NSMutableData dataWithLength:msgSize]; + GPBCodedOutputStream *outputStream = [[GPBCodedOutputStream alloc] initWithData:data]; + WriteDictUInt64Field(outputStream, key->valueUInt64, kMapKeyFieldNumber, keyType); + WriteDictEnumField(outputStream, value, kMapValueFieldNumber, GPBTypeEnum); + [outputStream release]; + return data; +} +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueEnum) forKey:@(key->valueUInt64)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndRawValuesUsingBlock:^(uint64_t key, int32_t value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%llu", key], @(value)); + }]; +} + +- (BOOL)valueForKey:(uint64_t)key value:(int32_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + int32_t result = [wrapped intValue]; + if (!_validationFunc(result)) { + result = kGPBUnrecognizedEnumeratorValue; + } + *value = result; + } + return (wrapped != NULL); +} + +- (BOOL)valueForKey:(uint64_t)key rawValue:(int32_t *)rawValue { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && rawValue) { + *rawValue = [wrapped intValue]; + } + return (wrapped != NULL); +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint64_t key, int32_t value, BOOL *stop))block { + GPBEnumValidationFunc func = _validationFunc; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + int32_t unwrapped = [aValue intValue]; + if (!func(unwrapped)) { + unwrapped = kGPBUnrecognizedEnumeratorValue; + } + block([aKey unsignedLongLongValue], unwrapped, stop); + }]; +} + +- (void)addRawEntriesFromDictionary:(GPBUInt64EnumDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setRawValue:(int32_t)value forKey:(uint64_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(uint64_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +- (void)setValue:(int32_t)value forKey:(uint64_t)key { + if (!_validationFunc(value)) { + [NSException raise:NSInvalidArgumentException + format:@"GPBUInt64EnumDictionary: Attempt to set an unknown enum value (%d)", + value]; + } + + [_dictionary setObject:@(value) forKey:@(key)]; +} + +@end + +#pragma mark - UInt64 -> Object + +@implementation GPBUInt64ObjectDictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(id)value + forKey:(uint64_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64ObjectDictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const id [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64ObjectDictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBUInt64ObjectDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBUInt64ObjectDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const id [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:values[i] forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBUInt64ObjectDictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBUInt64ObjectDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBUInt64ObjectDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBUInt64ObjectDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(uint64_t key, id value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + id aValue, + BOOL *stop) { + block([aKey unsignedLongLongValue], aValue, stop); + }]; +} + +- (BOOL)isInitialized { + for (GPBMessage *msg in [_dictionary objectEnumerator]) { + if (!msg.initialized) { + return NO; + } + } + return YES; +} + +- (instancetype)deepCopyWithZone:(NSZone *)zone { + GPBUInt64ObjectDictionary *newDict = + [[GPBUInt64ObjectDictionary alloc] init]; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(id aKey, + GPBMessage *msg, + BOOL *stop) { + #pragma unused(stop) + GPBMessage *copiedMsg = [msg copyWithZone:zone]; + [newDict->_dictionary setObject:copiedMsg forKey:aKey]; + [copiedMsg release]; + }]; + return newDict; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + id aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictObjectFieldSize(aValue, kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + id aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictObjectFieldSize(aValue, kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictUInt64Field(outputStream, [aKey unsignedLongLongValue], kMapKeyFieldNumber, keyType); + WriteDictObjectField(outputStream, aValue, kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:value->valueString forKey:@(key->valueUInt64)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(uint64_t key, id value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%llu", key], value); + }]; +} + +- (id)valueForKey:(uint64_t)key { + id result = [_dictionary objectForKey:@(key)]; + return result; +} + +- (void)addEntriesFromDictionary:(GPBUInt64ObjectDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(id)value forKey:(uint64_t)key { + [_dictionary setObject:value forKey:@(key)]; +} + +- (void)removeValueForKey:(uint64_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +//%PDDM-EXPAND DICTIONARY_IMPL_FOR_POD_KEY(Int64, int64_t) +// This block of code is generated, do not edit it directly. + +#pragma mark - Int64 -> UInt32 + +@implementation GPBInt64UInt32Dictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(uint32_t)value + forKey:(int64_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64UInt32Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const uint32_t [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64UInt32Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBInt64UInt32Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64UInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const uint32_t [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBInt64UInt32Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBInt64UInt32Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBInt64UInt32Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBInt64UInt32Dictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int64_t key, uint32_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey longLongValue], [aValue unsignedIntValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictUInt32FieldSize([aValue unsignedIntValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictUInt32FieldSize([aValue unsignedIntValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictInt64Field(outputStream, [aKey longLongValue], kMapKeyFieldNumber, keyType); + WriteDictUInt32Field(outputStream, [aValue unsignedIntValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueUInt32) forKey:@(key->valueInt64)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(int64_t key, uint32_t value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%lld", key], [NSString stringWithFormat:@"%u", value]); + }]; +} + +- (BOOL)valueForKey:(int64_t)key value:(uint32_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped unsignedIntValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBInt64UInt32Dictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(uint32_t)value forKey:(int64_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(int64_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - Int64 -> Int32 + +@implementation GPBInt64Int32Dictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(int32_t)value + forKey:(int64_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64Int32Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const int32_t [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64Int32Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBInt64Int32Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64Int32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBInt64Int32Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBInt64Int32Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBInt64Int32Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBInt64Int32Dictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int64_t key, int32_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey longLongValue], [aValue intValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictInt32FieldSize([aValue intValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictInt32FieldSize([aValue intValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictInt64Field(outputStream, [aKey longLongValue], kMapKeyFieldNumber, keyType); + WriteDictInt32Field(outputStream, [aValue intValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueInt32) forKey:@(key->valueInt64)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(int64_t key, int32_t value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%lld", key], [NSString stringWithFormat:@"%d", value]); + }]; +} + +- (BOOL)valueForKey:(int64_t)key value:(int32_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped intValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBInt64Int32Dictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(int32_t)value forKey:(int64_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(int64_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - Int64 -> UInt64 + +@implementation GPBInt64UInt64Dictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(uint64_t)value + forKey:(int64_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64UInt64Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const uint64_t [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64UInt64Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBInt64UInt64Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64UInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const uint64_t [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBInt64UInt64Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBInt64UInt64Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBInt64UInt64Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBInt64UInt64Dictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int64_t key, uint64_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey longLongValue], [aValue unsignedLongLongValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictUInt64FieldSize([aValue unsignedLongLongValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictUInt64FieldSize([aValue unsignedLongLongValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictInt64Field(outputStream, [aKey longLongValue], kMapKeyFieldNumber, keyType); + WriteDictUInt64Field(outputStream, [aValue unsignedLongLongValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueUInt64) forKey:@(key->valueInt64)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(int64_t key, uint64_t value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%lld", key], [NSString stringWithFormat:@"%llu", value]); + }]; +} + +- (BOOL)valueForKey:(int64_t)key value:(uint64_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped unsignedLongLongValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBInt64UInt64Dictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(uint64_t)value forKey:(int64_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(int64_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - Int64 -> Int64 + +@implementation GPBInt64Int64Dictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(int64_t)value + forKey:(int64_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64Int64Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const int64_t [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64Int64Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBInt64Int64Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64Int64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const int64_t [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBInt64Int64Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBInt64Int64Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBInt64Int64Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBInt64Int64Dictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int64_t key, int64_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey longLongValue], [aValue longLongValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictInt64FieldSize([aValue longLongValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictInt64FieldSize([aValue longLongValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictInt64Field(outputStream, [aKey longLongValue], kMapKeyFieldNumber, keyType); + WriteDictInt64Field(outputStream, [aValue longLongValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueInt64) forKey:@(key->valueInt64)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(int64_t key, int64_t value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%lld", key], [NSString stringWithFormat:@"%lld", value]); + }]; +} + +- (BOOL)valueForKey:(int64_t)key value:(int64_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped longLongValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBInt64Int64Dictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(int64_t)value forKey:(int64_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(int64_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - Int64 -> Bool + +@implementation GPBInt64BoolDictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(BOOL)value + forKey:(int64_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64BoolDictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const BOOL [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64BoolDictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBInt64BoolDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64BoolDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const BOOL [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBInt64BoolDictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBInt64BoolDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBInt64BoolDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBInt64BoolDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int64_t key, BOOL value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey longLongValue], [aValue boolValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictBoolFieldSize([aValue boolValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictBoolFieldSize([aValue boolValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictInt64Field(outputStream, [aKey longLongValue], kMapKeyFieldNumber, keyType); + WriteDictBoolField(outputStream, [aValue boolValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueBool) forKey:@(key->valueInt64)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(int64_t key, BOOL value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%lld", key], (value ? @"true" : @"false")); + }]; +} + +- (BOOL)valueForKey:(int64_t)key value:(BOOL *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped boolValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBInt64BoolDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(BOOL)value forKey:(int64_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(int64_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - Int64 -> Float + +@implementation GPBInt64FloatDictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(float)value + forKey:(int64_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64FloatDictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const float [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64FloatDictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBInt64FloatDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64FloatDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const float [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBInt64FloatDictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBInt64FloatDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBInt64FloatDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBInt64FloatDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int64_t key, float value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey longLongValue], [aValue floatValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictFloatFieldSize([aValue floatValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictFloatFieldSize([aValue floatValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictInt64Field(outputStream, [aKey longLongValue], kMapKeyFieldNumber, keyType); + WriteDictFloatField(outputStream, [aValue floatValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueFloat) forKey:@(key->valueInt64)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(int64_t key, float value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%lld", key], [NSString stringWithFormat:@"%.*g", FLT_DIG, value]); + }]; +} + +- (BOOL)valueForKey:(int64_t)key value:(float *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped floatValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBInt64FloatDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(float)value forKey:(int64_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(int64_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - Int64 -> Double + +@implementation GPBInt64DoubleDictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(double)value + forKey:(int64_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64DoubleDictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const double [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64DoubleDictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBInt64DoubleDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64DoubleDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const double [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBInt64DoubleDictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBInt64DoubleDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBInt64DoubleDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBInt64DoubleDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int64_t key, double value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey longLongValue], [aValue doubleValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictDoubleFieldSize([aValue doubleValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictDoubleFieldSize([aValue doubleValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictInt64Field(outputStream, [aKey longLongValue], kMapKeyFieldNumber, keyType); + WriteDictDoubleField(outputStream, [aValue doubleValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueDouble) forKey:@(key->valueInt64)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(int64_t key, double value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%lld", key], [NSString stringWithFormat:@"%.*lg", DBL_DIG, value]); + }]; +} + +- (BOOL)valueForKey:(int64_t)key value:(double *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + *value = [wrapped doubleValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBInt64DoubleDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(double)value forKey:(int64_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(int64_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - Int64 -> Enum + +@implementation GPBInt64EnumDictionary { + @package + NSMutableDictionary *_dictionary; + GPBEnumValidationFunc _validationFunc; +} + +@synthesize validationFunc = _validationFunc; + ++ (instancetype)dictionary { + return [[[self alloc] initWithValidationFunction:NULL + rawValues:NULL + forKeys:NULL + count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func { + return [[[self alloc] initWithValidationFunction:func + rawValues:NULL + forKeys:NULL + count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValue:(int32_t)rawValue + forKey:(int64_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64EnumDictionary*)[self alloc] initWithValidationFunction:func + rawValues:&rawValue + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])rawValues + forKeys:(const int64_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64EnumDictionary*)[self alloc] initWithValidationFunction:func + rawValues:rawValues + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBInt64EnumDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64EnumDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems { + return [[[self alloc] initWithValidationFunction:func capacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValidationFunction:NULL rawValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func { + return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])rawValues + forKeys:(const int64_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + _validationFunc = (func != NULL ? func : DictDefault_IsValidValue); + if (count && rawValues && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(rawValues[i]) forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBInt64EnumDictionary *)dictionary { + self = [self initWithValidationFunction:dictionary.validationFunc + rawValues:NULL + forKeys:NULL + count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBInt64EnumDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBInt64EnumDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBInt64EnumDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndRawValuesUsingBlock: + (void (^)(int64_t key, int32_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + block([aKey longLongValue], [aValue intValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictEnumFieldSize([aValue intValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictEnumFieldSize([aValue intValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictInt64Field(outputStream, [aKey longLongValue], kMapKeyFieldNumber, keyType); + WriteDictEnumField(outputStream, [aValue intValue], kMapValueFieldNumber, valueType); + }]; +} + +- (NSData *)serializedDataForUnknownValue:(int32_t)value + forKey:(GPBValue *)key + keyType:(GPBType)keyType { + size_t msgSize = ComputeDictInt64FieldSize(key->valueInt64, kMapKeyFieldNumber, keyType); + msgSize += ComputeDictEnumFieldSize(value, kMapValueFieldNumber, GPBTypeEnum); + NSMutableData *data = [NSMutableData dataWithLength:msgSize]; + GPBCodedOutputStream *outputStream = [[GPBCodedOutputStream alloc] initWithData:data]; + WriteDictInt64Field(outputStream, key->valueInt64, kMapKeyFieldNumber, keyType); + WriteDictEnumField(outputStream, value, kMapValueFieldNumber, GPBTypeEnum); + [outputStream release]; + return data; +} +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueEnum) forKey:@(key->valueInt64)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndRawValuesUsingBlock:^(int64_t key, int32_t value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%lld", key], @(value)); + }]; +} + +- (BOOL)valueForKey:(int64_t)key value:(int32_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && value) { + int32_t result = [wrapped intValue]; + if (!_validationFunc(result)) { + result = kGPBUnrecognizedEnumeratorValue; + } + *value = result; + } + return (wrapped != NULL); +} + +- (BOOL)valueForKey:(int64_t)key rawValue:(int32_t *)rawValue { + NSNumber *wrapped = [_dictionary objectForKey:@(key)]; + if (wrapped && rawValue) { + *rawValue = [wrapped intValue]; + } + return (wrapped != NULL); +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int64_t key, int32_t value, BOOL *stop))block { + GPBEnumValidationFunc func = _validationFunc; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + NSNumber *aValue, + BOOL *stop) { + int32_t unwrapped = [aValue intValue]; + if (!func(unwrapped)) { + unwrapped = kGPBUnrecognizedEnumeratorValue; + } + block([aKey longLongValue], unwrapped, stop); + }]; +} + +- (void)addRawEntriesFromDictionary:(GPBInt64EnumDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setRawValue:(int32_t)value forKey:(int64_t)key { + [_dictionary setObject:@(value) forKey:@(key)]; +} + +- (void)removeValueForKey:(int64_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +- (void)setValue:(int32_t)value forKey:(int64_t)key { + if (!_validationFunc(value)) { + [NSException raise:NSInvalidArgumentException + format:@"GPBInt64EnumDictionary: Attempt to set an unknown enum value (%d)", + value]; + } + + [_dictionary setObject:@(value) forKey:@(key)]; +} + +@end + +#pragma mark - Int64 -> Object + +@implementation GPBInt64ObjectDictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(id)value + forKey:(int64_t)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64ObjectDictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const id [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64ObjectDictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBInt64ObjectDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBInt64ObjectDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const id [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:values[i] forKey:@(keys[i])]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBInt64ObjectDictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBInt64ObjectDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBInt64ObjectDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBInt64ObjectDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(int64_t key, id value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + id aValue, + BOOL *stop) { + block([aKey longLongValue], aValue, stop); + }]; +} + +- (BOOL)isInitialized { + for (GPBMessage *msg in [_dictionary objectEnumerator]) { + if (!msg.initialized) { + return NO; + } + } + return YES; +} + +- (instancetype)deepCopyWithZone:(NSZone *)zone { + GPBInt64ObjectDictionary *newDict = + [[GPBInt64ObjectDictionary alloc] init]; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(id aKey, + GPBMessage *msg, + BOOL *stop) { + #pragma unused(stop) + GPBMessage *copiedMsg = [msg copyWithZone:zone]; + [newDict->_dictionary setObject:copiedMsg forKey:aKey]; + [copiedMsg release]; + }]; + return newDict; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + id aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictObjectFieldSize(aValue, kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey, + id aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyType); + msgSize += ComputeDictObjectFieldSize(aValue, kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictInt64Field(outputStream, [aKey longLongValue], kMapKeyFieldNumber, keyType); + WriteDictObjectField(outputStream, aValue, kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:value->valueString forKey:@(key->valueInt64)]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(int64_t key, id value, BOOL *stop) { + #pragma unused(stop) + block([NSString stringWithFormat:@"%lld", key], value); + }]; +} + +- (id)valueForKey:(int64_t)key { + id result = [_dictionary objectForKey:@(key)]; + return result; +} + +- (void)addEntriesFromDictionary:(GPBInt64ObjectDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(id)value forKey:(int64_t)key { + [_dictionary setObject:value forKey:@(key)]; +} + +- (void)removeValueForKey:(int64_t)aKey { + [_dictionary removeObjectForKey:@(aKey)]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +//%PDDM-EXPAND DICTIONARY_POD_IMPL_FOR_KEY(String, NSString, *, OBJECT) +// This block of code is generated, do not edit it directly. + +#pragma mark - String -> UInt32 + +@implementation GPBStringUInt32Dictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(uint32_t)value + forKey:(NSString *)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringUInt32Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const uint32_t [])values + forKeys:(const NSString * [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringUInt32Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBStringUInt32Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringUInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const uint32_t [])values + forKeys:(const NSString * [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:keys[i]]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBStringUInt32Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBStringUInt32Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBStringUInt32Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBStringUInt32Dictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(NSString *key, uint32_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + block(aKey, [aValue unsignedIntValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyType); + msgSize += ComputeDictUInt32FieldSize([aValue unsignedIntValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyType); + msgSize += ComputeDictUInt32FieldSize([aValue unsignedIntValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictStringField(outputStream, aKey, kMapKeyFieldNumber, keyType); + WriteDictUInt32Field(outputStream, [aValue unsignedIntValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueUInt32) forKey:key->valueString]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(NSString *key, uint32_t value, BOOL *stop) { + #pragma unused(stop) + block(key, [NSString stringWithFormat:@"%u", value]); + }]; +} + +- (BOOL)valueForKey:(NSString *)key value:(uint32_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:key]; + if (wrapped && value) { + *value = [wrapped unsignedIntValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBStringUInt32Dictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(uint32_t)value forKey:(NSString *)key { + [_dictionary setObject:@(value) forKey:key]; +} + +- (void)removeValueForKey:(NSString *)aKey { + [_dictionary removeObjectForKey:aKey]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - String -> Int32 + +@implementation GPBStringInt32Dictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(int32_t)value + forKey:(NSString *)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringInt32Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const int32_t [])values + forKeys:(const NSString * [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringInt32Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBStringInt32Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const NSString * [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:keys[i]]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBStringInt32Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBStringInt32Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBStringInt32Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBStringInt32Dictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(NSString *key, int32_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + block(aKey, [aValue intValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyType); + msgSize += ComputeDictInt32FieldSize([aValue intValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyType); + msgSize += ComputeDictInt32FieldSize([aValue intValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictStringField(outputStream, aKey, kMapKeyFieldNumber, keyType); + WriteDictInt32Field(outputStream, [aValue intValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueInt32) forKey:key->valueString]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(NSString *key, int32_t value, BOOL *stop) { + #pragma unused(stop) + block(key, [NSString stringWithFormat:@"%d", value]); + }]; +} + +- (BOOL)valueForKey:(NSString *)key value:(int32_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:key]; + if (wrapped && value) { + *value = [wrapped intValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBStringInt32Dictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(int32_t)value forKey:(NSString *)key { + [_dictionary setObject:@(value) forKey:key]; +} + +- (void)removeValueForKey:(NSString *)aKey { + [_dictionary removeObjectForKey:aKey]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - String -> UInt64 + +@implementation GPBStringUInt64Dictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(uint64_t)value + forKey:(NSString *)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringUInt64Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const uint64_t [])values + forKeys:(const NSString * [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringUInt64Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBStringUInt64Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringUInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const uint64_t [])values + forKeys:(const NSString * [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:keys[i]]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBStringUInt64Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBStringUInt64Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBStringUInt64Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBStringUInt64Dictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(NSString *key, uint64_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + block(aKey, [aValue unsignedLongLongValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyType); + msgSize += ComputeDictUInt64FieldSize([aValue unsignedLongLongValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyType); + msgSize += ComputeDictUInt64FieldSize([aValue unsignedLongLongValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictStringField(outputStream, aKey, kMapKeyFieldNumber, keyType); + WriteDictUInt64Field(outputStream, [aValue unsignedLongLongValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueUInt64) forKey:key->valueString]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(NSString *key, uint64_t value, BOOL *stop) { + #pragma unused(stop) + block(key, [NSString stringWithFormat:@"%llu", value]); + }]; +} + +- (BOOL)valueForKey:(NSString *)key value:(uint64_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:key]; + if (wrapped && value) { + *value = [wrapped unsignedLongLongValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBStringUInt64Dictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(uint64_t)value forKey:(NSString *)key { + [_dictionary setObject:@(value) forKey:key]; +} + +- (void)removeValueForKey:(NSString *)aKey { + [_dictionary removeObjectForKey:aKey]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - String -> Int64 + +@implementation GPBStringInt64Dictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(int64_t)value + forKey:(NSString *)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringInt64Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const int64_t [])values + forKeys:(const NSString * [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringInt64Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBStringInt64Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const int64_t [])values + forKeys:(const NSString * [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:keys[i]]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBStringInt64Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBStringInt64Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBStringInt64Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBStringInt64Dictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(NSString *key, int64_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + block(aKey, [aValue longLongValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyType); + msgSize += ComputeDictInt64FieldSize([aValue longLongValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyType); + msgSize += ComputeDictInt64FieldSize([aValue longLongValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictStringField(outputStream, aKey, kMapKeyFieldNumber, keyType); + WriteDictInt64Field(outputStream, [aValue longLongValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueInt64) forKey:key->valueString]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(NSString *key, int64_t value, BOOL *stop) { + #pragma unused(stop) + block(key, [NSString stringWithFormat:@"%lld", value]); + }]; +} + +- (BOOL)valueForKey:(NSString *)key value:(int64_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:key]; + if (wrapped && value) { + *value = [wrapped longLongValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBStringInt64Dictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(int64_t)value forKey:(NSString *)key { + [_dictionary setObject:@(value) forKey:key]; +} + +- (void)removeValueForKey:(NSString *)aKey { + [_dictionary removeObjectForKey:aKey]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - String -> Bool + +@implementation GPBStringBoolDictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(BOOL)value + forKey:(NSString *)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringBoolDictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const BOOL [])values + forKeys:(const NSString * [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringBoolDictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBStringBoolDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringBoolDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const BOOL [])values + forKeys:(const NSString * [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:keys[i]]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBStringBoolDictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBStringBoolDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBStringBoolDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBStringBoolDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(NSString *key, BOOL value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + block(aKey, [aValue boolValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyType); + msgSize += ComputeDictBoolFieldSize([aValue boolValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyType); + msgSize += ComputeDictBoolFieldSize([aValue boolValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictStringField(outputStream, aKey, kMapKeyFieldNumber, keyType); + WriteDictBoolField(outputStream, [aValue boolValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueBool) forKey:key->valueString]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(NSString *key, BOOL value, BOOL *stop) { + #pragma unused(stop) + block(key, (value ? @"true" : @"false")); + }]; +} + +- (BOOL)valueForKey:(NSString *)key value:(BOOL *)value { + NSNumber *wrapped = [_dictionary objectForKey:key]; + if (wrapped && value) { + *value = [wrapped boolValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBStringBoolDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(BOOL)value forKey:(NSString *)key { + [_dictionary setObject:@(value) forKey:key]; +} + +- (void)removeValueForKey:(NSString *)aKey { + [_dictionary removeObjectForKey:aKey]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - String -> Float + +@implementation GPBStringFloatDictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(float)value + forKey:(NSString *)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringFloatDictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const float [])values + forKeys:(const NSString * [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringFloatDictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBStringFloatDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringFloatDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const float [])values + forKeys:(const NSString * [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:keys[i]]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBStringFloatDictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBStringFloatDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBStringFloatDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBStringFloatDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(NSString *key, float value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + block(aKey, [aValue floatValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyType); + msgSize += ComputeDictFloatFieldSize([aValue floatValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyType); + msgSize += ComputeDictFloatFieldSize([aValue floatValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictStringField(outputStream, aKey, kMapKeyFieldNumber, keyType); + WriteDictFloatField(outputStream, [aValue floatValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueFloat) forKey:key->valueString]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(NSString *key, float value, BOOL *stop) { + #pragma unused(stop) + block(key, [NSString stringWithFormat:@"%.*g", FLT_DIG, value]); + }]; +} + +- (BOOL)valueForKey:(NSString *)key value:(float *)value { + NSNumber *wrapped = [_dictionary objectForKey:key]; + if (wrapped && value) { + *value = [wrapped floatValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBStringFloatDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(float)value forKey:(NSString *)key { + [_dictionary setObject:@(value) forKey:key]; +} + +- (void)removeValueForKey:(NSString *)aKey { + [_dictionary removeObjectForKey:aKey]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - String -> Double + +@implementation GPBStringDoubleDictionary { + @package + NSMutableDictionary *_dictionary; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(double)value + forKey:(NSString *)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringDoubleDictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const double [])values + forKeys:(const NSString * [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringDoubleDictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBStringDoubleDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringDoubleDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const double [])values + forKeys:(const NSString * [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + if (count && values && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(values[i]) forKey:keys[i]]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBStringDoubleDictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBStringDoubleDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBStringDoubleDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBStringDoubleDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(NSString *key, double value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + block(aKey, [aValue doubleValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyType); + msgSize += ComputeDictDoubleFieldSize([aValue doubleValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyType); + msgSize += ComputeDictDoubleFieldSize([aValue doubleValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictStringField(outputStream, aKey, kMapKeyFieldNumber, keyType); + WriteDictDoubleField(outputStream, [aValue doubleValue], kMapValueFieldNumber, valueType); + }]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueDouble) forKey:key->valueString]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndValuesUsingBlock:^(NSString *key, double value, BOOL *stop) { + #pragma unused(stop) + block(key, [NSString stringWithFormat:@"%.*lg", DBL_DIG, value]); + }]; +} + +- (BOOL)valueForKey:(NSString *)key value:(double *)value { + NSNumber *wrapped = [_dictionary objectForKey:key]; + if (wrapped && value) { + *value = [wrapped doubleValue]; + } + return (wrapped != NULL); +} + +- (void)addEntriesFromDictionary:(GPBStringDoubleDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setValue:(double)value forKey:(NSString *)key { + [_dictionary setObject:@(value) forKey:key]; +} + +- (void)removeValueForKey:(NSString *)aKey { + [_dictionary removeObjectForKey:aKey]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +@end + +#pragma mark - String -> Enum + +@implementation GPBStringEnumDictionary { + @package + NSMutableDictionary *_dictionary; + GPBEnumValidationFunc _validationFunc; +} + +@synthesize validationFunc = _validationFunc; + ++ (instancetype)dictionary { + return [[[self alloc] initWithValidationFunction:NULL + rawValues:NULL + forKeys:NULL + count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func { + return [[[self alloc] initWithValidationFunction:func + rawValues:NULL + forKeys:NULL + count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValue:(int32_t)rawValue + forKey:(NSString *)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringEnumDictionary*)[self alloc] initWithValidationFunction:func + rawValues:&rawValue + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])rawValues + forKeys:(const NSString * [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringEnumDictionary*)[self alloc] initWithValidationFunction:func + rawValues:rawValues + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBStringEnumDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBStringEnumDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems { + return [[[self alloc] initWithValidationFunction:func capacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValidationFunction:NULL rawValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func { + return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])rawValues + forKeys:(const NSString * [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _dictionary = [[NSMutableDictionary alloc] init]; + _validationFunc = (func != NULL ? func : DictDefault_IsValidValue); + if (count && rawValues && keys) { + for (NSUInteger i = 0; i < count; ++i) { + [_dictionary setObject:@(rawValues[i]) forKey:keys[i]]; + } + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBStringEnumDictionary *)dictionary { + self = [self initWithValidationFunction:dictionary.validationFunc + rawValues:NULL + forKeys:NULL + count:0]; + if (self) { + if (dictionary) { + [_dictionary addEntriesFromDictionary:dictionary->_dictionary]; + } + } + return self; +} + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_dictionary release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBStringEnumDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBStringEnumDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBStringEnumDictionary class]]) { + return NO; + } + return [_dictionary isEqual:other->_dictionary]; +} + +- (NSUInteger)hash { + return _dictionary.count; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> { %@ }", [self class], self, _dictionary]; +} + +- (NSUInteger)count { + return _dictionary.count; +} + +- (void)enumerateKeysAndRawValuesUsingBlock: + (void (^)(NSString *key, int32_t value, BOOL *stop))block { + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + block(aKey, [aValue intValue], stop); + }]; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + NSUInteger count = _dictionary.count; + if (count == 0) { + return 0; + } + + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + __block size_t result = 0; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyType); + msgSize += ComputeDictEnumFieldSize([aValue intValue], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + }]; + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + GPBType keyType = field.mapKeyType; + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + #pragma unused(stop) + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictStringFieldSize(aKey, kMapKeyFieldNumber, keyType); + msgSize += ComputeDictEnumFieldSize([aValue intValue], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictStringField(outputStream, aKey, kMapKeyFieldNumber, keyType); + WriteDictEnumField(outputStream, [aValue intValue], kMapValueFieldNumber, valueType); + }]; +} + +- (NSData *)serializedDataForUnknownValue:(int32_t)value + forKey:(GPBValue *)key + keyType:(GPBType)keyType { + size_t msgSize = ComputeDictStringFieldSize(key->valueString, kMapKeyFieldNumber, keyType); + msgSize += ComputeDictEnumFieldSize(value, kMapValueFieldNumber, GPBTypeEnum); + NSMutableData *data = [NSMutableData dataWithLength:msgSize]; + GPBCodedOutputStream *outputStream = [[GPBCodedOutputStream alloc] initWithData:data]; + WriteDictStringField(outputStream, key->valueString, kMapKeyFieldNumber, keyType); + WriteDictEnumField(outputStream, value, kMapValueFieldNumber, GPBTypeEnum); + [outputStream release]; + return data; +} +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + [_dictionary setObject:@(value->valueEnum) forKey:key->valueString]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + [self enumerateKeysAndRawValuesUsingBlock:^(NSString *key, int32_t value, BOOL *stop) { + #pragma unused(stop) + block(key, @(value)); + }]; +} + +- (BOOL)valueForKey:(NSString *)key value:(int32_t *)value { + NSNumber *wrapped = [_dictionary objectForKey:key]; + if (wrapped && value) { + int32_t result = [wrapped intValue]; + if (!_validationFunc(result)) { + result = kGPBUnrecognizedEnumeratorValue; + } + *value = result; + } + return (wrapped != NULL); +} + +- (BOOL)valueForKey:(NSString *)key rawValue:(int32_t *)rawValue { + NSNumber *wrapped = [_dictionary objectForKey:key]; + if (wrapped && rawValue) { + *rawValue = [wrapped intValue]; + } + return (wrapped != NULL); +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(NSString *key, int32_t value, BOOL *stop))block { + GPBEnumValidationFunc func = _validationFunc; + [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *aKey, + NSNumber *aValue, + BOOL *stop) { + int32_t unwrapped = [aValue intValue]; + if (!func(unwrapped)) { + unwrapped = kGPBUnrecognizedEnumeratorValue; + } + block(aKey, unwrapped, stop); + }]; +} + +- (void)addRawEntriesFromDictionary:(GPBStringEnumDictionary *)otherDictionary { + if (otherDictionary) { + [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary]; + } +} + +- (void)setRawValue:(int32_t)value forKey:(NSString *)key { + [_dictionary setObject:@(value) forKey:key]; +} + +- (void)removeValueForKey:(NSString *)aKey { + [_dictionary removeObjectForKey:aKey]; +} + +- (void)removeAll { + [_dictionary removeAllObjects]; +} + +- (void)setValue:(int32_t)value forKey:(NSString *)key { + if (!_validationFunc(value)) { + [NSException raise:NSInvalidArgumentException + format:@"GPBStringEnumDictionary: Attempt to set an unknown enum value (%d)", + value]; + } + + [_dictionary setObject:@(value) forKey:key]; +} + +@end + +//%PDDM-EXPAND-END (5 expansions) + + +//%PDDM-EXPAND DICTIONARY_BOOL_KEY_TO_POD_IMPL(UInt32, uint32_t) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> UInt32 + +@implementation GPBBoolUInt32Dictionary { + @package + uint32_t _values[2]; + BOOL _valueSet[2]; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(uint32_t)value + forKey:(BOOL)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolUInt32Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const uint32_t [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolUInt32Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBBoolUInt32Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolUInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const uint32_t [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + for (NSUInteger i = 0; i < count; ++i) { + int idx = keys[i] ? 1 : 0; + _values[idx] = values[i]; + _valueSet[idx] = YES; + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBBoolUInt32Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + for (int i = 0; i < 2; ++i) { + if (dictionary->_valueSet[i]) { + _values[i] = dictionary->_values[i]; + _valueSet[i] = YES; + } + } + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBBoolUInt32Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBBoolUInt32Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBBoolUInt32Dictionary class]]) { + return NO; + } + if ((_valueSet[0] != other->_valueSet[0]) || + (_valueSet[1] != other->_valueSet[1])) { + return NO; + } + if ((_valueSet[0] && (_values[0] != other->_values[0])) || + (_valueSet[1] && (_values[1] != other->_values[1]))) { + return NO; + } + return YES; +} + +- (NSUInteger)hash { + return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0); +} + +- (NSString *)description { + NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> {", [self class], self]; + if (_valueSet[0]) { + [result appendFormat:@"NO: %u", _values[0]]; + } + if (_valueSet[1]) { + [result appendFormat:@"YES: %u", _values[1]]; + } + [result appendString:@" }"]; + return result; +} + +- (NSUInteger)count { + return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0); +} + +- (BOOL)valueForKey:(BOOL)key value:(uint32_t *)value { + int idx = (key ? 1 : 0); + if (_valueSet[idx]) { + if (value) { + *value = _values[idx]; + } + return YES; + } + return NO; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + int idx = (key->valueBool ? 1 : 0); + _values[idx] = value->valueUInt32; + _valueSet[idx] = YES; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + if (_valueSet[0]) { + block(@"false", [NSString stringWithFormat:@"%u", _values[0]]); + } + if (_valueSet[1]) { + block(@"true", [NSString stringWithFormat:@"%u", _values[1]]); + } +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(BOOL key, uint32_t value, BOOL *stop))block { + BOOL stop = NO; + if (_valueSet[0]) { + block(NO, _values[0], &stop); + } + if (!stop && _valueSet[1]) { + block(YES, _values[1], &stop); + } +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + NSUInteger count = 0; + size_t result = 0; + for (int i = 0; i < 2; ++i) { + if (_valueSet[i]) { + ++count; + size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBTypeBool); + msgSize += ComputeDictUInt32FieldSize(_values[i], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + } + } + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + for (int i = 0; i < 2; ++i) { + if (_valueSet[i]) { + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBTypeBool); + msgSize += ComputeDictUInt32FieldSize(_values[i], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictBoolField(outputStream, (i == 1), kMapKeyFieldNumber, GPBTypeBool); + WriteDictUInt32Field(outputStream, _values[i], kMapValueFieldNumber, valueType); + } + } +} + +- (void)addEntriesFromDictionary:(GPBBoolUInt32Dictionary *)otherDictionary { + if (otherDictionary) { + for (int i = 0; i < 2; ++i) { + if (otherDictionary->_valueSet[i]) { + _valueSet[i] = YES; + _values[i] = otherDictionary->_values[i]; + } + } + } +} + +- (void)setValue:(uint32_t)value forKey:(BOOL)key { + int idx = (key ? 1 : 0); + _values[idx] = value; + _valueSet[idx] = YES; +} + +- (void)removeValueForKey:(BOOL)aKey { + _valueSet[aKey ? 1 : 0] = NO; +} + +- (void)removeAll { + _valueSet[0] = NO; + _valueSet[1] = NO; +} + +@end + +//%PDDM-EXPAND DICTIONARY_BOOL_KEY_TO_POD_IMPL(Int32, int32_t) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> Int32 + +@implementation GPBBoolInt32Dictionary { + @package + int32_t _values[2]; + BOOL _valueSet[2]; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(int32_t)value + forKey:(BOOL)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolInt32Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const int32_t [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolInt32Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBBoolInt32Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + for (NSUInteger i = 0; i < count; ++i) { + int idx = keys[i] ? 1 : 0; + _values[idx] = values[i]; + _valueSet[idx] = YES; + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBBoolInt32Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + for (int i = 0; i < 2; ++i) { + if (dictionary->_valueSet[i]) { + _values[i] = dictionary->_values[i]; + _valueSet[i] = YES; + } + } + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBBoolInt32Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBBoolInt32Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBBoolInt32Dictionary class]]) { + return NO; + } + if ((_valueSet[0] != other->_valueSet[0]) || + (_valueSet[1] != other->_valueSet[1])) { + return NO; + } + if ((_valueSet[0] && (_values[0] != other->_values[0])) || + (_valueSet[1] && (_values[1] != other->_values[1]))) { + return NO; + } + return YES; +} + +- (NSUInteger)hash { + return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0); +} + +- (NSString *)description { + NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> {", [self class], self]; + if (_valueSet[0]) { + [result appendFormat:@"NO: %d", _values[0]]; + } + if (_valueSet[1]) { + [result appendFormat:@"YES: %d", _values[1]]; + } + [result appendString:@" }"]; + return result; +} + +- (NSUInteger)count { + return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0); +} + +- (BOOL)valueForKey:(BOOL)key value:(int32_t *)value { + int idx = (key ? 1 : 0); + if (_valueSet[idx]) { + if (value) { + *value = _values[idx]; + } + return YES; + } + return NO; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + int idx = (key->valueBool ? 1 : 0); + _values[idx] = value->valueInt32; + _valueSet[idx] = YES; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + if (_valueSet[0]) { + block(@"false", [NSString stringWithFormat:@"%d", _values[0]]); + } + if (_valueSet[1]) { + block(@"true", [NSString stringWithFormat:@"%d", _values[1]]); + } +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(BOOL key, int32_t value, BOOL *stop))block { + BOOL stop = NO; + if (_valueSet[0]) { + block(NO, _values[0], &stop); + } + if (!stop && _valueSet[1]) { + block(YES, _values[1], &stop); + } +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + NSUInteger count = 0; + size_t result = 0; + for (int i = 0; i < 2; ++i) { + if (_valueSet[i]) { + ++count; + size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBTypeBool); + msgSize += ComputeDictInt32FieldSize(_values[i], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + } + } + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + for (int i = 0; i < 2; ++i) { + if (_valueSet[i]) { + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBTypeBool); + msgSize += ComputeDictInt32FieldSize(_values[i], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictBoolField(outputStream, (i == 1), kMapKeyFieldNumber, GPBTypeBool); + WriteDictInt32Field(outputStream, _values[i], kMapValueFieldNumber, valueType); + } + } +} + +- (void)addEntriesFromDictionary:(GPBBoolInt32Dictionary *)otherDictionary { + if (otherDictionary) { + for (int i = 0; i < 2; ++i) { + if (otherDictionary->_valueSet[i]) { + _valueSet[i] = YES; + _values[i] = otherDictionary->_values[i]; + } + } + } +} + +- (void)setValue:(int32_t)value forKey:(BOOL)key { + int idx = (key ? 1 : 0); + _values[idx] = value; + _valueSet[idx] = YES; +} + +- (void)removeValueForKey:(BOOL)aKey { + _valueSet[aKey ? 1 : 0] = NO; +} + +- (void)removeAll { + _valueSet[0] = NO; + _valueSet[1] = NO; +} + +@end + +//%PDDM-EXPAND DICTIONARY_BOOL_KEY_TO_POD_IMPL(UInt64, uint64_t) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> UInt64 + +@implementation GPBBoolUInt64Dictionary { + @package + uint64_t _values[2]; + BOOL _valueSet[2]; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(uint64_t)value + forKey:(BOOL)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolUInt64Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const uint64_t [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolUInt64Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBBoolUInt64Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolUInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const uint64_t [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + for (NSUInteger i = 0; i < count; ++i) { + int idx = keys[i] ? 1 : 0; + _values[idx] = values[i]; + _valueSet[idx] = YES; + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBBoolUInt64Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + for (int i = 0; i < 2; ++i) { + if (dictionary->_valueSet[i]) { + _values[i] = dictionary->_values[i]; + _valueSet[i] = YES; + } + } + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBBoolUInt64Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBBoolUInt64Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBBoolUInt64Dictionary class]]) { + return NO; + } + if ((_valueSet[0] != other->_valueSet[0]) || + (_valueSet[1] != other->_valueSet[1])) { + return NO; + } + if ((_valueSet[0] && (_values[0] != other->_values[0])) || + (_valueSet[1] && (_values[1] != other->_values[1]))) { + return NO; + } + return YES; +} + +- (NSUInteger)hash { + return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0); +} + +- (NSString *)description { + NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> {", [self class], self]; + if (_valueSet[0]) { + [result appendFormat:@"NO: %llu", _values[0]]; + } + if (_valueSet[1]) { + [result appendFormat:@"YES: %llu", _values[1]]; + } + [result appendString:@" }"]; + return result; +} + +- (NSUInteger)count { + return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0); +} + +- (BOOL)valueForKey:(BOOL)key value:(uint64_t *)value { + int idx = (key ? 1 : 0); + if (_valueSet[idx]) { + if (value) { + *value = _values[idx]; + } + return YES; + } + return NO; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + int idx = (key->valueBool ? 1 : 0); + _values[idx] = value->valueUInt64; + _valueSet[idx] = YES; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + if (_valueSet[0]) { + block(@"false", [NSString stringWithFormat:@"%llu", _values[0]]); + } + if (_valueSet[1]) { + block(@"true", [NSString stringWithFormat:@"%llu", _values[1]]); + } +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(BOOL key, uint64_t value, BOOL *stop))block { + BOOL stop = NO; + if (_valueSet[0]) { + block(NO, _values[0], &stop); + } + if (!stop && _valueSet[1]) { + block(YES, _values[1], &stop); + } +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + NSUInteger count = 0; + size_t result = 0; + for (int i = 0; i < 2; ++i) { + if (_valueSet[i]) { + ++count; + size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBTypeBool); + msgSize += ComputeDictUInt64FieldSize(_values[i], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + } + } + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + for (int i = 0; i < 2; ++i) { + if (_valueSet[i]) { + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBTypeBool); + msgSize += ComputeDictUInt64FieldSize(_values[i], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictBoolField(outputStream, (i == 1), kMapKeyFieldNumber, GPBTypeBool); + WriteDictUInt64Field(outputStream, _values[i], kMapValueFieldNumber, valueType); + } + } +} + +- (void)addEntriesFromDictionary:(GPBBoolUInt64Dictionary *)otherDictionary { + if (otherDictionary) { + for (int i = 0; i < 2; ++i) { + if (otherDictionary->_valueSet[i]) { + _valueSet[i] = YES; + _values[i] = otherDictionary->_values[i]; + } + } + } +} + +- (void)setValue:(uint64_t)value forKey:(BOOL)key { + int idx = (key ? 1 : 0); + _values[idx] = value; + _valueSet[idx] = YES; +} + +- (void)removeValueForKey:(BOOL)aKey { + _valueSet[aKey ? 1 : 0] = NO; +} + +- (void)removeAll { + _valueSet[0] = NO; + _valueSet[1] = NO; +} + +@end + +//%PDDM-EXPAND DICTIONARY_BOOL_KEY_TO_POD_IMPL(Int64, int64_t) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> Int64 + +@implementation GPBBoolInt64Dictionary { + @package + int64_t _values[2]; + BOOL _valueSet[2]; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(int64_t)value + forKey:(BOOL)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolInt64Dictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const int64_t [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolInt64Dictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBBoolInt64Dictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const int64_t [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + for (NSUInteger i = 0; i < count; ++i) { + int idx = keys[i] ? 1 : 0; + _values[idx] = values[i]; + _valueSet[idx] = YES; + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBBoolInt64Dictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + for (int i = 0; i < 2; ++i) { + if (dictionary->_valueSet[i]) { + _values[i] = dictionary->_values[i]; + _valueSet[i] = YES; + } + } + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBBoolInt64Dictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBBoolInt64Dictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBBoolInt64Dictionary class]]) { + return NO; + } + if ((_valueSet[0] != other->_valueSet[0]) || + (_valueSet[1] != other->_valueSet[1])) { + return NO; + } + if ((_valueSet[0] && (_values[0] != other->_values[0])) || + (_valueSet[1] && (_values[1] != other->_values[1]))) { + return NO; + } + return YES; +} + +- (NSUInteger)hash { + return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0); +} + +- (NSString *)description { + NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> {", [self class], self]; + if (_valueSet[0]) { + [result appendFormat:@"NO: %lld", _values[0]]; + } + if (_valueSet[1]) { + [result appendFormat:@"YES: %lld", _values[1]]; + } + [result appendString:@" }"]; + return result; +} + +- (NSUInteger)count { + return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0); +} + +- (BOOL)valueForKey:(BOOL)key value:(int64_t *)value { + int idx = (key ? 1 : 0); + if (_valueSet[idx]) { + if (value) { + *value = _values[idx]; + } + return YES; + } + return NO; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + int idx = (key->valueBool ? 1 : 0); + _values[idx] = value->valueInt64; + _valueSet[idx] = YES; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + if (_valueSet[0]) { + block(@"false", [NSString stringWithFormat:@"%lld", _values[0]]); + } + if (_valueSet[1]) { + block(@"true", [NSString stringWithFormat:@"%lld", _values[1]]); + } +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(BOOL key, int64_t value, BOOL *stop))block { + BOOL stop = NO; + if (_valueSet[0]) { + block(NO, _values[0], &stop); + } + if (!stop && _valueSet[1]) { + block(YES, _values[1], &stop); + } +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + NSUInteger count = 0; + size_t result = 0; + for (int i = 0; i < 2; ++i) { + if (_valueSet[i]) { + ++count; + size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBTypeBool); + msgSize += ComputeDictInt64FieldSize(_values[i], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + } + } + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + for (int i = 0; i < 2; ++i) { + if (_valueSet[i]) { + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBTypeBool); + msgSize += ComputeDictInt64FieldSize(_values[i], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictBoolField(outputStream, (i == 1), kMapKeyFieldNumber, GPBTypeBool); + WriteDictInt64Field(outputStream, _values[i], kMapValueFieldNumber, valueType); + } + } +} + +- (void)addEntriesFromDictionary:(GPBBoolInt64Dictionary *)otherDictionary { + if (otherDictionary) { + for (int i = 0; i < 2; ++i) { + if (otherDictionary->_valueSet[i]) { + _valueSet[i] = YES; + _values[i] = otherDictionary->_values[i]; + } + } + } +} + +- (void)setValue:(int64_t)value forKey:(BOOL)key { + int idx = (key ? 1 : 0); + _values[idx] = value; + _valueSet[idx] = YES; +} + +- (void)removeValueForKey:(BOOL)aKey { + _valueSet[aKey ? 1 : 0] = NO; +} + +- (void)removeAll { + _valueSet[0] = NO; + _valueSet[1] = NO; +} + +@end + +//%PDDM-EXPAND DICTIONARY_BOOL_KEY_TO_POD_IMPL(Bool, BOOL) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> Bool + +@implementation GPBBoolBoolDictionary { + @package + BOOL _values[2]; + BOOL _valueSet[2]; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(BOOL)value + forKey:(BOOL)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolBoolDictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const BOOL [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolBoolDictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBBoolBoolDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolBoolDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const BOOL [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + for (NSUInteger i = 0; i < count; ++i) { + int idx = keys[i] ? 1 : 0; + _values[idx] = values[i]; + _valueSet[idx] = YES; + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBBoolBoolDictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + for (int i = 0; i < 2; ++i) { + if (dictionary->_valueSet[i]) { + _values[i] = dictionary->_values[i]; + _valueSet[i] = YES; + } + } + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBBoolBoolDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBBoolBoolDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBBoolBoolDictionary class]]) { + return NO; + } + if ((_valueSet[0] != other->_valueSet[0]) || + (_valueSet[1] != other->_valueSet[1])) { + return NO; + } + if ((_valueSet[0] && (_values[0] != other->_values[0])) || + (_valueSet[1] && (_values[1] != other->_values[1]))) { + return NO; + } + return YES; +} + +- (NSUInteger)hash { + return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0); +} + +- (NSString *)description { + NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> {", [self class], self]; + if (_valueSet[0]) { + [result appendFormat:@"NO: %d", _values[0]]; + } + if (_valueSet[1]) { + [result appendFormat:@"YES: %d", _values[1]]; + } + [result appendString:@" }"]; + return result; +} + +- (NSUInteger)count { + return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0); +} + +- (BOOL)valueForKey:(BOOL)key value:(BOOL *)value { + int idx = (key ? 1 : 0); + if (_valueSet[idx]) { + if (value) { + *value = _values[idx]; + } + return YES; + } + return NO; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + int idx = (key->valueBool ? 1 : 0); + _values[idx] = value->valueBool; + _valueSet[idx] = YES; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + if (_valueSet[0]) { + block(@"false", (_values[0] ? @"true" : @"false")); + } + if (_valueSet[1]) { + block(@"true", (_values[1] ? @"true" : @"false")); + } +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(BOOL key, BOOL value, BOOL *stop))block { + BOOL stop = NO; + if (_valueSet[0]) { + block(NO, _values[0], &stop); + } + if (!stop && _valueSet[1]) { + block(YES, _values[1], &stop); + } +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + NSUInteger count = 0; + size_t result = 0; + for (int i = 0; i < 2; ++i) { + if (_valueSet[i]) { + ++count; + size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBTypeBool); + msgSize += ComputeDictBoolFieldSize(_values[i], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + } + } + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + for (int i = 0; i < 2; ++i) { + if (_valueSet[i]) { + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBTypeBool); + msgSize += ComputeDictBoolFieldSize(_values[i], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictBoolField(outputStream, (i == 1), kMapKeyFieldNumber, GPBTypeBool); + WriteDictBoolField(outputStream, _values[i], kMapValueFieldNumber, valueType); + } + } +} + +- (void)addEntriesFromDictionary:(GPBBoolBoolDictionary *)otherDictionary { + if (otherDictionary) { + for (int i = 0; i < 2; ++i) { + if (otherDictionary->_valueSet[i]) { + _valueSet[i] = YES; + _values[i] = otherDictionary->_values[i]; + } + } + } +} + +- (void)setValue:(BOOL)value forKey:(BOOL)key { + int idx = (key ? 1 : 0); + _values[idx] = value; + _valueSet[idx] = YES; +} + +- (void)removeValueForKey:(BOOL)aKey { + _valueSet[aKey ? 1 : 0] = NO; +} + +- (void)removeAll { + _valueSet[0] = NO; + _valueSet[1] = NO; +} + +@end + +//%PDDM-EXPAND DICTIONARY_BOOL_KEY_TO_POD_IMPL(Float, float) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> Float + +@implementation GPBBoolFloatDictionary { + @package + float _values[2]; + BOOL _valueSet[2]; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(float)value + forKey:(BOOL)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolFloatDictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const float [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolFloatDictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBBoolFloatDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolFloatDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const float [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + for (NSUInteger i = 0; i < count; ++i) { + int idx = keys[i] ? 1 : 0; + _values[idx] = values[i]; + _valueSet[idx] = YES; + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBBoolFloatDictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + for (int i = 0; i < 2; ++i) { + if (dictionary->_valueSet[i]) { + _values[i] = dictionary->_values[i]; + _valueSet[i] = YES; + } + } + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBBoolFloatDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBBoolFloatDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBBoolFloatDictionary class]]) { + return NO; + } + if ((_valueSet[0] != other->_valueSet[0]) || + (_valueSet[1] != other->_valueSet[1])) { + return NO; + } + if ((_valueSet[0] && (_values[0] != other->_values[0])) || + (_valueSet[1] && (_values[1] != other->_values[1]))) { + return NO; + } + return YES; +} + +- (NSUInteger)hash { + return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0); +} + +- (NSString *)description { + NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> {", [self class], self]; + if (_valueSet[0]) { + [result appendFormat:@"NO: %f", _values[0]]; + } + if (_valueSet[1]) { + [result appendFormat:@"YES: %f", _values[1]]; + } + [result appendString:@" }"]; + return result; +} + +- (NSUInteger)count { + return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0); +} + +- (BOOL)valueForKey:(BOOL)key value:(float *)value { + int idx = (key ? 1 : 0); + if (_valueSet[idx]) { + if (value) { + *value = _values[idx]; + } + return YES; + } + return NO; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + int idx = (key->valueBool ? 1 : 0); + _values[idx] = value->valueFloat; + _valueSet[idx] = YES; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + if (_valueSet[0]) { + block(@"false", [NSString stringWithFormat:@"%.*g", FLT_DIG, _values[0]]); + } + if (_valueSet[1]) { + block(@"true", [NSString stringWithFormat:@"%.*g", FLT_DIG, _values[1]]); + } +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(BOOL key, float value, BOOL *stop))block { + BOOL stop = NO; + if (_valueSet[0]) { + block(NO, _values[0], &stop); + } + if (!stop && _valueSet[1]) { + block(YES, _values[1], &stop); + } +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + NSUInteger count = 0; + size_t result = 0; + for (int i = 0; i < 2; ++i) { + if (_valueSet[i]) { + ++count; + size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBTypeBool); + msgSize += ComputeDictFloatFieldSize(_values[i], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + } + } + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + for (int i = 0; i < 2; ++i) { + if (_valueSet[i]) { + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBTypeBool); + msgSize += ComputeDictFloatFieldSize(_values[i], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictBoolField(outputStream, (i == 1), kMapKeyFieldNumber, GPBTypeBool); + WriteDictFloatField(outputStream, _values[i], kMapValueFieldNumber, valueType); + } + } +} + +- (void)addEntriesFromDictionary:(GPBBoolFloatDictionary *)otherDictionary { + if (otherDictionary) { + for (int i = 0; i < 2; ++i) { + if (otherDictionary->_valueSet[i]) { + _valueSet[i] = YES; + _values[i] = otherDictionary->_values[i]; + } + } + } +} + +- (void)setValue:(float)value forKey:(BOOL)key { + int idx = (key ? 1 : 0); + _values[idx] = value; + _valueSet[idx] = YES; +} + +- (void)removeValueForKey:(BOOL)aKey { + _valueSet[aKey ? 1 : 0] = NO; +} + +- (void)removeAll { + _valueSet[0] = NO; + _valueSet[1] = NO; +} + +@end + +//%PDDM-EXPAND DICTIONARY_BOOL_KEY_TO_POD_IMPL(Double, double) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> Double + +@implementation GPBBoolDoubleDictionary { + @package + double _values[2]; + BOOL _valueSet[2]; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(double)value + forKey:(BOOL)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolDoubleDictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const double [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolDoubleDictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBBoolDoubleDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolDoubleDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const double [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + for (NSUInteger i = 0; i < count; ++i) { + int idx = keys[i] ? 1 : 0; + _values[idx] = values[i]; + _valueSet[idx] = YES; + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBBoolDoubleDictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + for (int i = 0; i < 2; ++i) { + if (dictionary->_valueSet[i]) { + _values[i] = dictionary->_values[i]; + _valueSet[i] = YES; + } + } + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBBoolDoubleDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBBoolDoubleDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBBoolDoubleDictionary class]]) { + return NO; + } + if ((_valueSet[0] != other->_valueSet[0]) || + (_valueSet[1] != other->_valueSet[1])) { + return NO; + } + if ((_valueSet[0] && (_values[0] != other->_values[0])) || + (_valueSet[1] && (_values[1] != other->_values[1]))) { + return NO; + } + return YES; +} + +- (NSUInteger)hash { + return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0); +} + +- (NSString *)description { + NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> {", [self class], self]; + if (_valueSet[0]) { + [result appendFormat:@"NO: %lf", _values[0]]; + } + if (_valueSet[1]) { + [result appendFormat:@"YES: %lf", _values[1]]; + } + [result appendString:@" }"]; + return result; +} + +- (NSUInteger)count { + return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0); +} + +- (BOOL)valueForKey:(BOOL)key value:(double *)value { + int idx = (key ? 1 : 0); + if (_valueSet[idx]) { + if (value) { + *value = _values[idx]; + } + return YES; + } + return NO; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + int idx = (key->valueBool ? 1 : 0); + _values[idx] = value->valueDouble; + _valueSet[idx] = YES; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + if (_valueSet[0]) { + block(@"false", [NSString stringWithFormat:@"%.*lg", DBL_DIG, _values[0]]); + } + if (_valueSet[1]) { + block(@"true", [NSString stringWithFormat:@"%.*lg", DBL_DIG, _values[1]]); + } +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(BOOL key, double value, BOOL *stop))block { + BOOL stop = NO; + if (_valueSet[0]) { + block(NO, _values[0], &stop); + } + if (!stop && _valueSet[1]) { + block(YES, _values[1], &stop); + } +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + NSUInteger count = 0; + size_t result = 0; + for (int i = 0; i < 2; ++i) { + if (_valueSet[i]) { + ++count; + size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBTypeBool); + msgSize += ComputeDictDoubleFieldSize(_values[i], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + } + } + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + for (int i = 0; i < 2; ++i) { + if (_valueSet[i]) { + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBTypeBool); + msgSize += ComputeDictDoubleFieldSize(_values[i], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictBoolField(outputStream, (i == 1), kMapKeyFieldNumber, GPBTypeBool); + WriteDictDoubleField(outputStream, _values[i], kMapValueFieldNumber, valueType); + } + } +} + +- (void)addEntriesFromDictionary:(GPBBoolDoubleDictionary *)otherDictionary { + if (otherDictionary) { + for (int i = 0; i < 2; ++i) { + if (otherDictionary->_valueSet[i]) { + _valueSet[i] = YES; + _values[i] = otherDictionary->_values[i]; + } + } + } +} + +- (void)setValue:(double)value forKey:(BOOL)key { + int idx = (key ? 1 : 0); + _values[idx] = value; + _valueSet[idx] = YES; +} + +- (void)removeValueForKey:(BOOL)aKey { + _valueSet[aKey ? 1 : 0] = NO; +} + +- (void)removeAll { + _valueSet[0] = NO; + _valueSet[1] = NO; +} + +@end + +//%PDDM-EXPAND DICTIONARY_BOOL_KEY_TO_OBJECT_IMPL(Object, id) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> Object + +@implementation GPBBoolObjectDictionary { + @package + id _values[2]; +} + ++ (instancetype)dictionary { + return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValue:(id)value + forKey:(BOOL)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolObjectDictionary*)[self alloc] initWithValues:&value + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValues:(const id [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolObjectDictionary*)[self alloc] initWithValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBBoolObjectDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolObjectDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems { + return [[[self alloc] initWithCapacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValues:(const id [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + for (NSUInteger i = 0; i < count; ++i) { + int idx = keys[i] ? 1 : 0; + [_values[idx] release]; + _values[idx] = (id)[values[i] retain]; + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBBoolObjectDictionary *)dictionary { + self = [self initWithValues:NULL forKeys:NULL count:0]; + if (self) { + if (dictionary) { + _values[0] = [dictionary->_values[0] retain]; + _values[1] = [dictionary->_values[1] retain]; + } + } + return self; +} + +- (instancetype)initWithCapacity:(NSUInteger)numItems { + #pragma unused(numItems) + return [self initWithValues:NULL forKeys:NULL count:0]; +} + +- (void)dealloc { + [_values[0] release]; + [_values[1] release]; + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBBoolObjectDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBBoolObjectDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBBoolObjectDictionary class]]) { + return NO; + } + if (((_values[0] != nil) != (other->_values[0] != nil)) || + ((_values[1] != nil) != (other->_values[1] != nil))) { + return NO; + } + if (((_values[0] != nil) && (![_values[0] isEqual:other->_values[0]])) || + ((_values[1] != nil) && (![_values[1] isEqual:other->_values[1]]))) { + return NO; + } + return YES; +} + +- (NSUInteger)hash { + return ((_values[0] != nil) ? 1 : 0) + ((_values[1] != nil) ? 1 : 0); +} + +- (NSString *)description { + NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> {", [self class], self]; + if ((_values[0] != nil)) { + [result appendFormat:@"NO: %@", _values[0]]; + } + if ((_values[1] != nil)) { + [result appendFormat:@"YES: %@", _values[1]]; + } + [result appendString:@" }"]; + return result; +} + +- (NSUInteger)count { + return ((_values[0] != nil) ? 1 : 0) + ((_values[1] != nil) ? 1 : 0); +} + +- (id)valueForKey:(BOOL)key { + return _values[key ? 1 : 0]; +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + int idx = (key->valueBool ? 1 : 0); + [_values[idx] release]; + _values[idx] = [value->valueString retain]; +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + if (_values[0] != nil) { + block(@"false", _values[0]); + } + if ((_values[1] != nil)) { + block(@"true", _values[1]); + } +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(BOOL key, id value, BOOL *stop))block { + BOOL stop = NO; + if (_values[0] != nil) { + block(NO, _values[0], &stop); + } + if (!stop && (_values[1] != nil)) { + block(YES, _values[1], &stop); + } +} + +- (BOOL)isInitialized { + if (_values[0] && ![_values[0] isInitialized]) { + return NO; + } + if (_values[1] && ![_values[1] isInitialized]) { + return NO; + } + return YES; +} + +- (instancetype)deepCopyWithZone:(NSZone *)zone { + GPBBoolObjectDictionary *newDict = + [[GPBBoolObjectDictionary alloc] init]; + for (int i = 0; i < 2; ++i) { + if (_values[i] != nil) { + newDict->_values[i] = [_values[i] copyWithZone:zone]; + } + } + return newDict; +} + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + NSUInteger count = 0; + size_t result = 0; + for (int i = 0; i < 2; ++i) { + if (_values[i] != nil) { + ++count; + size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBTypeBool); + msgSize += ComputeDictObjectFieldSize(_values[i], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + } + } + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + for (int i = 0; i < 2; ++i) { + if (_values[i] != nil) { + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBTypeBool); + msgSize += ComputeDictObjectFieldSize(_values[i], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictBoolField(outputStream, (i == 1), kMapKeyFieldNumber, GPBTypeBool); + WriteDictObjectField(outputStream, _values[i], kMapValueFieldNumber, valueType); + } + } +} + +- (void)addEntriesFromDictionary:(GPBBoolObjectDictionary *)otherDictionary { + if (otherDictionary) { + for (int i = 0; i < 2; ++i) { + if (otherDictionary->_values[i] != nil) { + [_values[i] release]; + _values[i] = [otherDictionary->_values[i] retain]; + } + } + } +} + +- (void)setValue:(id)value forKey:(BOOL)key { + int idx = (key ? 1 : 0); + [_values[idx] release]; + _values[idx] = [value retain]; +} + +- (void)removeValueForKey:(BOOL)aKey { + int idx = (aKey ? 1 : 0); + [_values[idx] release]; + _values[idx] = nil; +} + +- (void)removeAll { + for (int i = 0; i < 2; ++i) { + [_values[i] release]; + _values[i] = nil; + } +} + +@end + +//%PDDM-EXPAND-END (8 expansions) + +#pragma mark - Bool -> Enum + +@implementation GPBBoolEnumDictionary { + @package + GPBEnumValidationFunc _validationFunc; + int32_t _values[2]; + BOOL _valueSet[2]; +} + +@synthesize validationFunc = _validationFunc; + ++ (instancetype)dictionary { + return [[[self alloc] initWithValidationFunction:NULL + rawValues:NULL + forKeys:NULL + count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func { + return [[[self alloc] initWithValidationFunction:func + rawValues:NULL + forKeys:NULL + count:0] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValue:(int32_t)rawValue + forKey:(BOOL)key { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolEnumDictionary*)[self alloc] initWithValidationFunction:func + rawValues:&rawValue + forKeys:&key + count:1] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])values + forKeys:(const BOOL [])keys + count:(NSUInteger)count { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolEnumDictionary*)[self alloc] initWithValidationFunction:func + rawValues:values + forKeys:keys + count:count] autorelease]; +} + ++ (instancetype)dictionaryWithDictionary:(GPBBoolEnumDictionary *)dictionary { + // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count: + // on to get the type correct. + return [[(GPBBoolEnumDictionary*)[self alloc] initWithDictionary:dictionary] autorelease]; +} + ++ (instancetype)dictionaryWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems { + return [[[self alloc] initWithValidationFunction:func capacity:numItems] autorelease]; +} + +- (instancetype)init { + return [self initWithValidationFunction:NULL rawValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func { + return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + rawValues:(const int32_t [])rawValues + forKeys:(const BOOL [])keys + count:(NSUInteger)count { + self = [super init]; + if (self) { + _validationFunc = (func != NULL ? func : DictDefault_IsValidValue); + for (NSUInteger i = 0; i < count; ++i) { + int idx = keys[i] ? 1 : 0; + _values[idx] = rawValues[i]; + _valueSet[idx] = YES; + } + } + return self; +} + +- (instancetype)initWithDictionary:(GPBBoolEnumDictionary *)dictionary { + self = [self initWithValidationFunction:dictionary.validationFunc + rawValues:NULL + forKeys:NULL + count:0]; + if (self) { + if (dictionary) { + for (int i = 0; i < 2; ++i) { + if (dictionary->_valueSet[i]) { + _values[i] = dictionary->_values[i]; + _valueSet[i] = YES; + } + } + } + } + return self; +} + +- (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func + capacity:(NSUInteger)numItems { +#pragma unused(numItems) + return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[GPBBoolEnumDictionary allocWithZone:zone] initWithDictionary:self]; +} + +- (BOOL)isEqual:(GPBBoolEnumDictionary *)other { + if (self == other) { + return YES; + } + if (![other isKindOfClass:[GPBBoolEnumDictionary class]]) { + return NO; + } + if ((_valueSet[0] != other->_valueSet[0]) || + (_valueSet[1] != other->_valueSet[1])) { + return NO; + } + if ((_valueSet[0] && (_values[0] != other->_values[0])) || + (_valueSet[1] && (_values[1] != other->_values[1]))) { + return NO; + } + return YES; +} + +- (NSUInteger)hash { + return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0); +} + +- (NSString *)description { + NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p> {", [self class], self]; + if (_valueSet[0]) { + [result appendFormat:@"NO: %d", _values[0]]; + } + if (_valueSet[1]) { + [result appendFormat:@"YES: %d", _values[1]]; + } + [result appendString:@" }"]; + return result; +} + +- (NSUInteger)count { + return (_valueSet[0] ? 1 : 0) + (_valueSet[1] ? 1 : 0); +} + +- (BOOL)valueForKey:(BOOL)key value:(int32_t*)value { + int idx = (key ? 1 : 0); + if (_valueSet[idx]) { + if (value) { + int32_t result = _values[idx]; + if (!_validationFunc(result)) { + result = kGPBUnrecognizedEnumeratorValue; + } + *value = result; + } + return YES; + } + return NO; +} + +- (BOOL)valueForKey:(BOOL)key rawValue:(int32_t*)rawValue { + int idx = (key ? 1 : 0); + if (_valueSet[idx]) { + if (rawValue) { + *rawValue = _values[idx]; + } + return YES; + } + return NO; +} + +- (void)enumerateKeysAndValuesUsingBlock: + (void (^)(BOOL key, int32_t value, BOOL *stop))block { + BOOL stop = NO; + if (_valueSet[0]) { + block(NO, _values[0], &stop); + } + if (!stop && _valueSet[1]) { + block(YES, _values[1], &stop); + } +} + +- (void)enumerateKeysAndRawValuesUsingBlock: + (void (^)(BOOL key, int32_t rawValue, BOOL *stop))block { + BOOL stop = NO; + GPBEnumValidationFunc func = _validationFunc; + int32_t validatedValue; + if (_valueSet[0]) { + validatedValue = _values[0]; + if (!func(validatedValue)) { + validatedValue = kGPBUnrecognizedEnumeratorValue; + } + block(NO, validatedValue, &stop); + } + if (!stop && _valueSet[1]) { + validatedValue = _values[1]; + if (!func(validatedValue)) { + validatedValue = kGPBUnrecognizedEnumeratorValue; + } + block(YES, validatedValue, &stop); + } +} + +//%PDDM-EXPAND SERIAL_DATA_FOR_ENTRY_POD_Enum(Bool) +// This block of code is generated, do not edit it directly. + +- (NSData *)serializedDataForUnknownValue:(int32_t)value + forKey:(GPBValue *)key + keyType:(GPBType)keyType { + size_t msgSize = ComputeDictBoolFieldSize(key->valueBool, kMapKeyFieldNumber, keyType); + msgSize += ComputeDictEnumFieldSize(value, kMapValueFieldNumber, GPBTypeEnum); + NSMutableData *data = [NSMutableData dataWithLength:msgSize]; + GPBCodedOutputStream *outputStream = [[GPBCodedOutputStream alloc] initWithData:data]; + WriteDictBoolField(outputStream, key->valueBool, kMapKeyFieldNumber, keyType); + WriteDictEnumField(outputStream, value, kMapValueFieldNumber, GPBTypeEnum); + [outputStream release]; + return data; +} + +//%PDDM-EXPAND-END SERIAL_DATA_FOR_ENTRY_POD_Enum(Bool) + +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + NSUInteger count = 0; + size_t result = 0; + for (int i = 0; i < 2; ++i) { + if (_valueSet[i]) { + ++count; + size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBTypeBool); + msgSize += ComputeDictInt32FieldSize(_values[i], kMapValueFieldNumber, valueType); + result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize; + } + } + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBTypeMessage); + result += tagSize * count; + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field { + GPBType valueType = GPBGetFieldType(field); + uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited); + for (int i = 0; i < 2; ++i) { + if (_valueSet[i]) { + // Write the tag. + [outputStream writeInt32NoTag:tag]; + // Write the size of the message. + size_t msgSize = ComputeDictBoolFieldSize((i == 1), kMapKeyFieldNumber, GPBTypeBool); + msgSize += ComputeDictInt32FieldSize(_values[i], kMapValueFieldNumber, valueType); + [outputStream writeInt32NoTag:(int32_t)msgSize]; + // Write the fields. + WriteDictBoolField(outputStream, (i == 1), kMapKeyFieldNumber, GPBTypeBool); + WriteDictInt32Field(outputStream, _values[i], kMapValueFieldNumber, valueType); + } + } +} + +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block { + if (_valueSet[0]) { + block(@"false", @(_values[0])); + } + if (_valueSet[1]) { + block(@"true", @(_values[1])); + } +} + +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key { + int idx = (key->valueBool ? 1 : 0); + _values[idx] = value->valueInt32; + _valueSet[idx] = YES; +} + +- (void)addRawEntriesFromDictionary:(GPBBoolEnumDictionary *)otherDictionary { + if (otherDictionary) { + for (int i = 0; i < 2; ++i) { + if (otherDictionary->_valueSet[i]) { + _valueSet[i] = YES; + _values[i] = otherDictionary->_values[i]; + } + } + } +} + +- (void)setValue:(int32_t)value forKey:(BOOL)key { + if (!_validationFunc(value)) { + [NSException raise:NSInvalidArgumentException + format:@"GPBBoolEnumDictionary: Attempt to set an unknown enum value (%d)", + value]; + } + int idx = (key ? 1 : 0); + _values[idx] = value; + _valueSet[idx] = YES; +} + +- (void)setRawValue:(int32_t)rawValue forKey:(BOOL)key { + int idx = (key ? 1 : 0); + _values[idx] = rawValue; + _valueSet[idx] = YES; +} + +- (void)removeValueForKey:(BOOL)aKey { + _valueSet[aKey ? 1 : 0] = NO; +} + +- (void)removeAll { + _valueSet[0] = NO; + _valueSet[1] = NO; +} + +@end diff --git a/objectivec/GPBDictionary_PackagePrivate.h b/objectivec/GPBDictionary_PackagePrivate.h new file mode 100644 index 00000000..54b37dd8 --- /dev/null +++ b/objectivec/GPBDictionary_PackagePrivate.h @@ -0,0 +1,577 @@ +// 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. + +#import <Foundation/Foundation.h> + +#import "GPBDictionary.h" + +@class GPBCodedInputStream; +@class GPBCodedOutputStream; +@class GPBExtensionRegistry; +@class GPBFieldDescriptor; + +//%PDDM-DEFINE DICTIONARY_PRIV_INTERFACES_FOR_POD_KEY(KEY_NAME) +//%DICTIONARY_POD_PRIV_INTERFACES_FOR_KEY(KEY_NAME) +//%DICTIONARY_PRIVATE_INTERFACES(KEY_NAME, Object, Object) +//%PDDM-DEFINE DICTIONARY_POD_PRIV_INTERFACES_FOR_KEY(KEY_NAME) +//%DICTIONARY_PRIVATE_INTERFACES(KEY_NAME, UInt32, Basic) +//%DICTIONARY_PRIVATE_INTERFACES(KEY_NAME, Int32, Basic) +//%DICTIONARY_PRIVATE_INTERFACES(KEY_NAME, UInt64, Basic) +//%DICTIONARY_PRIVATE_INTERFACES(KEY_NAME, Int64, Basic) +//%DICTIONARY_PRIVATE_INTERFACES(KEY_NAME, Bool, Basic) +//%DICTIONARY_PRIVATE_INTERFACES(KEY_NAME, Float, Basic) +//%DICTIONARY_PRIVATE_INTERFACES(KEY_NAME, Double, Basic) +//%DICTIONARY_PRIVATE_INTERFACES(KEY_NAME, Enum, Enum) + +//%PDDM-DEFINE DICTIONARY_PRIVATE_INTERFACES(KEY_NAME, VALUE_NAME, HELPER) +//%@interface GPB##KEY_NAME##VALUE_NAME##Dictionary () +//%- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +//%- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream +//% asField:(GPBFieldDescriptor *)field; +//%- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +//%- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +//%EXTRA_DICTIONARY_PRIVATE_INTERFACES_##HELPER()@end +//% + +//%PDDM-DEFINE EXTRA_DICTIONARY_PRIVATE_INTERFACES_Basic() +// Empty +//%PDDM-DEFINE EXTRA_DICTIONARY_PRIVATE_INTERFACES_Object() +//%- (BOOL)isInitialized; +//%- (instancetype)deepCopyWithZone:(NSZone *)zone +//% __attribute__((ns_returns_retained)); +//% +//%PDDM-DEFINE EXTRA_DICTIONARY_PRIVATE_INTERFACES_Enum() +//%- (NSData *)serializedDataForUnknownValue:(int32_t)value +//% forKey:(GPBValue *)key +//% keyType:(GPBType)keyType; +//% + +//%PDDM-EXPAND DICTIONARY_PRIV_INTERFACES_FOR_POD_KEY(UInt32) +// This block of code is generated, do not edit it directly. + +@interface GPBUInt32UInt32Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBUInt32Int32Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBUInt32UInt64Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBUInt32Int64Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBUInt32BoolDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBUInt32FloatDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBUInt32DoubleDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBUInt32EnumDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +- (NSData *)serializedDataForUnknownValue:(int32_t)value + forKey:(GPBValue *)key + keyType:(GPBType)keyType; +@end + +@interface GPBUInt32ObjectDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +- (BOOL)isInitialized; +- (instancetype)deepCopyWithZone:(NSZone *)zone + __attribute__((ns_returns_retained)); +@end + +//%PDDM-EXPAND DICTIONARY_PRIV_INTERFACES_FOR_POD_KEY(Int32) +// This block of code is generated, do not edit it directly. + +@interface GPBInt32UInt32Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBInt32Int32Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBInt32UInt64Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBInt32Int64Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBInt32BoolDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBInt32FloatDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBInt32DoubleDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBInt32EnumDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +- (NSData *)serializedDataForUnknownValue:(int32_t)value + forKey:(GPBValue *)key + keyType:(GPBType)keyType; +@end + +@interface GPBInt32ObjectDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +- (BOOL)isInitialized; +- (instancetype)deepCopyWithZone:(NSZone *)zone + __attribute__((ns_returns_retained)); +@end + +//%PDDM-EXPAND DICTIONARY_PRIV_INTERFACES_FOR_POD_KEY(UInt64) +// This block of code is generated, do not edit it directly. + +@interface GPBUInt64UInt32Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBUInt64Int32Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBUInt64UInt64Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBUInt64Int64Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBUInt64BoolDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBUInt64FloatDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBUInt64DoubleDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBUInt64EnumDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +- (NSData *)serializedDataForUnknownValue:(int32_t)value + forKey:(GPBValue *)key + keyType:(GPBType)keyType; +@end + +@interface GPBUInt64ObjectDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +- (BOOL)isInitialized; +- (instancetype)deepCopyWithZone:(NSZone *)zone + __attribute__((ns_returns_retained)); +@end + +//%PDDM-EXPAND DICTIONARY_PRIV_INTERFACES_FOR_POD_KEY(Int64) +// This block of code is generated, do not edit it directly. + +@interface GPBInt64UInt32Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBInt64Int32Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBInt64UInt64Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBInt64Int64Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBInt64BoolDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBInt64FloatDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBInt64DoubleDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBInt64EnumDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +- (NSData *)serializedDataForUnknownValue:(int32_t)value + forKey:(GPBValue *)key + keyType:(GPBType)keyType; +@end + +@interface GPBInt64ObjectDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +- (BOOL)isInitialized; +- (instancetype)deepCopyWithZone:(NSZone *)zone + __attribute__((ns_returns_retained)); +@end + +//%PDDM-EXPAND DICTIONARY_PRIV_INTERFACES_FOR_POD_KEY(Bool) +// This block of code is generated, do not edit it directly. + +@interface GPBBoolUInt32Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBBoolInt32Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBBoolUInt64Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBBoolInt64Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBBoolBoolDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBBoolFloatDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBBoolDoubleDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBBoolEnumDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +- (NSData *)serializedDataForUnknownValue:(int32_t)value + forKey:(GPBValue *)key + keyType:(GPBType)keyType; +@end + +@interface GPBBoolObjectDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +- (BOOL)isInitialized; +- (instancetype)deepCopyWithZone:(NSZone *)zone + __attribute__((ns_returns_retained)); +@end + +//%PDDM-EXPAND DICTIONARY_POD_PRIV_INTERFACES_FOR_KEY(String) +// This block of code is generated, do not edit it directly. + +@interface GPBStringUInt32Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBStringInt32Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBStringUInt64Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBStringInt64Dictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBStringBoolDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBStringFloatDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBStringDoubleDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +@end + +@interface GPBStringEnumDictionary () +- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field; +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream + asField:(GPBFieldDescriptor *)field; +- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key; +- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block; +- (NSData *)serializedDataForUnknownValue:(int32_t)value + forKey:(GPBValue *)key + keyType:(GPBType)keyType; +@end + +//%PDDM-EXPAND-END (6 expansions) + +CF_EXTERN_C_BEGIN + +// Helper to compute size when an NSDictionary is used for the map instead +// of a custom type. +size_t GPBDictionaryComputeSizeInternalHelper(NSDictionary *dict, + GPBFieldDescriptor *field); + +// Helper to write out when an NSDictionary is used for the map instead +// of a custom type. +void GPBDictionaryWriteToStreamInternalHelper( + GPBCodedOutputStream *outputStream, NSDictionary *dict, + GPBFieldDescriptor *field); + +// Helper to check message initialization when an NSDictionary is used for +// the map instead of a custom type. +BOOL GPBDictionaryIsInitializedInternalHelper(NSDictionary *dict, + GPBFieldDescriptor *field); + +// Helper to read a map instead. +void GPBDictionaryReadEntry(id mapDictionary, GPBCodedInputStream *stream, + GPBExtensionRegistry *registry, + GPBFieldDescriptor *field, + GPBMessage *parentMessage); + +CF_EXTERN_C_END diff --git a/objectivec/GPBExtensionField.h b/objectivec/GPBExtensionField.h new file mode 100644 index 00000000..e5ba1561 --- /dev/null +++ b/objectivec/GPBExtensionField.h @@ -0,0 +1,51 @@ +// 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. + +#import <Foundation/Foundation.h> + +#import "GPBWireFormat.h" +#import "GPBTypes.h" + +@class GPBCodedInputStream; +@class GPBCodedOutputStream; +@class GPBExtensionRegistry; +@class GPBDescriptor; +@class GPBExtensionDescriptor; + +@interface GPBExtensionField : NSObject<NSCopying> + +@property(nonatomic, readonly) int32_t fieldNumber; +@property(nonatomic, readonly) GPBWireFormat wireType; +@property(nonatomic, readonly) BOOL isRepeated; +@property(nonatomic, readonly) GPBDescriptor *containingType; +@property(nonatomic, readonly) id defaultValue; +@property(nonatomic, readonly) GPBExtensionDescriptor *descriptor; + +@end diff --git a/objectivec/GPBExtensionField.m b/objectivec/GPBExtensionField.m new file mode 100644 index 00000000..bbb36d7f --- /dev/null +++ b/objectivec/GPBExtensionField.m @@ -0,0 +1,525 @@ +// 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. + +#import "GPBExtensionField_PackagePrivate.h" + +#import <objc/runtime.h> + +#import "GPBCodedInputStream_PackagePrivate.h" +#import "GPBCodedOutputStream.h" +#import "GPBDescriptor_PackagePrivate.h" +#import "GPBMessage_PackagePrivate.h" +#import "GPBUtilities_PackagePrivate.h" + +GPB_INLINE size_t TypeSize(GPBType type) { + switch (type) { + case GPBTypeBool: + return 1; + case GPBTypeFixed32: + case GPBTypeSFixed32: + case GPBTypeFloat: + return 4; + case GPBTypeFixed64: + case GPBTypeSFixed64: + case GPBTypeDouble: + return 8; + default: + return 0; + } +} + +GPB_INLINE BOOL ExtensionIsRepeated(GPBExtensionDescription *description) { + return (description->options & GPBExtensionRepeated) != 0; +} + +GPB_INLINE BOOL ExtensionIsPacked(GPBExtensionDescription *description) { + return (description->options & GPBExtensionPacked) != 0; +} + +GPB_INLINE BOOL ExtensionIsWireFormat(GPBExtensionDescription *description) { + return (description->options & GPBExtensionSetWireFormat) != 0; +} + +static size_t ComputePBSerializedSizeNoTagOfObject(GPBType type, id object) { +#define FIELD_CASE(TYPE, ACCESSOR) \ + case GPBType##TYPE: \ + return GPBCompute##TYPE##SizeNoTag([(NSNumber *)object ACCESSOR]); +#define FIELD_CASE2(TYPE) \ + case GPBType##TYPE: \ + return GPBCompute##TYPE##SizeNoTag(object); + switch (type) { + FIELD_CASE(Bool, boolValue) + FIELD_CASE(Float, floatValue) + FIELD_CASE(Double, doubleValue) + FIELD_CASE(Int32, intValue) + FIELD_CASE(SFixed32, intValue) + FIELD_CASE(SInt32, intValue) + FIELD_CASE(Enum, intValue) + FIELD_CASE(Int64, longLongValue) + FIELD_CASE(SInt64, longLongValue) + FIELD_CASE(SFixed64, longLongValue) + FIELD_CASE(UInt32, unsignedIntValue) + FIELD_CASE(Fixed32, unsignedIntValue) + FIELD_CASE(UInt64, unsignedLongLongValue) + FIELD_CASE(Fixed64, unsignedLongLongValue) + FIELD_CASE2(Data) + FIELD_CASE2(String) + FIELD_CASE2(Message) + FIELD_CASE2(Group) + } +#undef FIELD_CASE +#undef FIELD_CASE2 +} + +static size_t ComputeSerializedSizeIncludingTagOfObject( + GPBExtensionDescription *description, id object) { +#define FIELD_CASE(TYPE, ACCESSOR) \ + case GPBType##TYPE: \ + return GPBCompute##TYPE##Size(description->fieldNumber, \ + [(NSNumber *)object ACCESSOR]); +#define FIELD_CASE2(TYPE) \ + case GPBType##TYPE: \ + return GPBCompute##TYPE##Size(description->fieldNumber, object); + switch (description->type) { + FIELD_CASE(Bool, boolValue) + FIELD_CASE(Float, floatValue) + FIELD_CASE(Double, doubleValue) + FIELD_CASE(Int32, intValue) + FIELD_CASE(SFixed32, intValue) + FIELD_CASE(SInt32, intValue) + FIELD_CASE(Enum, intValue) + FIELD_CASE(Int64, longLongValue) + FIELD_CASE(SInt64, longLongValue) + FIELD_CASE(SFixed64, longLongValue) + FIELD_CASE(UInt32, unsignedIntValue) + FIELD_CASE(Fixed32, unsignedIntValue) + FIELD_CASE(UInt64, unsignedLongLongValue) + FIELD_CASE(Fixed64, unsignedLongLongValue) + FIELD_CASE2(Data) + FIELD_CASE2(String) + FIELD_CASE2(Group) + case GPBTypeMessage: + if (ExtensionIsWireFormat(description)) { + return GPBComputeMessageSetExtensionSize(description->fieldNumber, + object); + } else { + return GPBComputeMessageSize(description->fieldNumber, object); + } + } +#undef FIELD_CASE +#undef FIELD_CASE2 +} + +static size_t ComputeSerializedSizeIncludingTagOfArray( + GPBExtensionDescription *description, NSArray *values) { + if (ExtensionIsPacked(description)) { + size_t size = 0; + size_t typeSize = TypeSize(description->type); + if (typeSize != 0) { + size = values.count * typeSize; + } else { + for (id value in values) { + size += ComputePBSerializedSizeNoTagOfObject(description->type, value); + } + } + return size + GPBComputeTagSize(description->fieldNumber) + + GPBComputeRawVarint32SizeForInteger(size); + } else { + size_t size = 0; + for (id value in values) { + size += ComputeSerializedSizeIncludingTagOfObject(description, value); + } + return size; + } +} + +static void WriteObjectIncludingTagToCodedOutputStream( + id object, GPBExtensionDescription *description, + GPBCodedOutputStream *output) { +#define FIELD_CASE(TYPE, ACCESSOR) \ + case GPBType##TYPE: \ + [output write##TYPE:description->fieldNumber \ + value:[(NSNumber *)object ACCESSOR]]; \ + return; +#define FIELD_CASE2(TYPE) \ + case GPBType##TYPE: \ + [output write##TYPE:description->fieldNumber value:object]; \ + return; + switch (description->type) { + FIELD_CASE(Bool, boolValue) + FIELD_CASE(Float, floatValue) + FIELD_CASE(Double, doubleValue) + FIELD_CASE(Int32, intValue) + FIELD_CASE(SFixed32, intValue) + FIELD_CASE(SInt32, intValue) + FIELD_CASE(Enum, intValue) + FIELD_CASE(Int64, longLongValue) + FIELD_CASE(SInt64, longLongValue) + FIELD_CASE(SFixed64, longLongValue) + FIELD_CASE(UInt32, unsignedIntValue) + FIELD_CASE(Fixed32, unsignedIntValue) + FIELD_CASE(UInt64, unsignedLongLongValue) + FIELD_CASE(Fixed64, unsignedLongLongValue) + FIELD_CASE2(Data) + FIELD_CASE2(String) + FIELD_CASE2(Group) + case GPBTypeMessage: + if (ExtensionIsWireFormat(description)) { + [output writeMessageSetExtension:description->fieldNumber value:object]; + } else { + [output writeMessage:description->fieldNumber value:object]; + } + return; + } +#undef FIELD_CASE +#undef FIELD_CASE2 +} + +static void WriteObjectNoTagToCodedOutputStream( + id object, GPBExtensionDescription *description, + GPBCodedOutputStream *output) { +#define FIELD_CASE(TYPE, ACCESSOR) \ + case GPBType##TYPE: \ + [output write##TYPE##NoTag:[(NSNumber *)object ACCESSOR]]; \ + return; +#define FIELD_CASE2(TYPE) \ + case GPBType##TYPE: \ + [output write##TYPE##NoTag:object]; \ + return; + switch (description->type) { + FIELD_CASE(Bool, boolValue) + FIELD_CASE(Float, floatValue) + FIELD_CASE(Double, doubleValue) + FIELD_CASE(Int32, intValue) + FIELD_CASE(SFixed32, intValue) + FIELD_CASE(SInt32, intValue) + FIELD_CASE(Enum, intValue) + FIELD_CASE(Int64, longLongValue) + FIELD_CASE(SInt64, longLongValue) + FIELD_CASE(SFixed64, longLongValue) + FIELD_CASE(UInt32, unsignedIntValue) + FIELD_CASE(Fixed32, unsignedIntValue) + FIELD_CASE(UInt64, unsignedLongLongValue) + FIELD_CASE(Fixed64, unsignedLongLongValue) + FIELD_CASE2(Data) + FIELD_CASE2(String) + FIELD_CASE2(Message) + case GPBTypeGroup: + [output writeGroupNoTag:description->fieldNumber value:object]; + return; + } +#undef FIELD_CASE +#undef FIELD_CASE2 +} + +static void WriteArrayIncludingTagsToCodedOutputStream( + NSArray *values, GPBExtensionDescription *description, + GPBCodedOutputStream *output) { + if (ExtensionIsPacked(description)) { + [output writeTag:description->fieldNumber + format:GPBWireFormatLengthDelimited]; + size_t dataSize = 0; + size_t typeSize = TypeSize(description->type); + if (typeSize != 0) { + dataSize = values.count * typeSize; + } else { + for (id value in values) { + dataSize += + ComputePBSerializedSizeNoTagOfObject(description->type, value); + } + } + [output writeRawVarintSizeTAs32:dataSize]; + for (id value in values) { + WriteObjectNoTagToCodedOutputStream(value, description, output); + } + } else { + for (id value in values) { + WriteObjectIncludingTagToCodedOutputStream(value, description, output); + } + } +} + +@implementation GPBExtensionField { + GPBExtensionDescription *description_; + GPBExtensionDescriptor *descriptor_; + GPBValue defaultValue_; +} + +@synthesize containingType = containingType_; +@synthesize descriptor = descriptor_; + +- (instancetype)init { + // Throw an exception if people attempt to not use the designated initializer. + self = [super init]; + if (self != nil) { + [self doesNotRecognizeSelector:_cmd]; + self = nil; + } + return self; +} + +- (instancetype)initWithDescription:(GPBExtensionDescription *)description { + if ((self = [super init])) { + description_ = description; + if (description->extendedClass) { + Class containingClass = objc_lookUpClass(description->extendedClass); + NSAssert1(containingClass, @"Class %s not defined", + description->extendedClass); + containingType_ = [containingClass descriptor]; + } +#if DEBUG + const char *className = description->messageOrGroupClassName; + if (className) { + NSAssert1(objc_lookUpClass(className) != Nil, @"Class %s not defined", + className); + } +#endif + descriptor_ = [[GPBExtensionDescriptor alloc] + initWithExtensionDescription:description]; + GPBType type = description_->type; + if (type == GPBTypeData) { + // Data stored as a length prefixed c-string in descriptor records. + const uint8_t *bytes = + (const uint8_t *)description->defaultValue.valueData; + if (bytes) { + uint32_t length = *((uint32_t *)bytes); + // The length is stored in network byte order. + length = ntohl(length); + bytes += sizeof(length); + defaultValue_.valueData = + [[NSData alloc] initWithBytes:bytes length:length]; + } + } else if (type == GPBTypeMessage || type == GPBTypeGroup) { + // The default is looked up in -defaultValue instead since extensions + // aren't + // common, we avoid the hit startup hit and it avoid initialization order + // issues. + } else { + defaultValue_ = description->defaultValue; + } + } + return self; +} + +- (void)dealloc { + if ((description_->type == GPBTypeData) && + !ExtensionIsRepeated(description_)) { + [defaultValue_.valueData release]; + } + [descriptor_ release]; + [super dealloc]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@ %p> FieldNumber:%d ContainingType:%@", + [self class], self, self.fieldNumber, + self.containingType]; +} + +- (id)copyWithZone:(NSZone *)__unused zone { + return [self retain]; +} + +#pragma mark Properties + +- (int32_t)fieldNumber { + return description_->fieldNumber; +} + +- (GPBWireFormat)wireType { + return GPBWireFormatForType(description_->type, + ExtensionIsPacked(description_)); +} + +- (BOOL)isRepeated { + return ExtensionIsRepeated(description_); +} + +- (id)defaultValue { + if (ExtensionIsRepeated(description_)) { + return nil; + } + + switch (description_->type) { + case GPBTypeBool: + return @(defaultValue_.valueBool); + case GPBTypeFloat: + return @(defaultValue_.valueFloat); + case GPBTypeDouble: + return @(defaultValue_.valueDouble); + case GPBTypeInt32: + case GPBTypeSInt32: + case GPBTypeEnum: + case GPBTypeSFixed32: + return @(defaultValue_.valueInt32); + case GPBTypeInt64: + case GPBTypeSInt64: + case GPBTypeSFixed64: + return @(defaultValue_.valueInt64); + case GPBTypeUInt32: + case GPBTypeFixed32: + return @(defaultValue_.valueUInt32); + case GPBTypeUInt64: + case GPBTypeFixed64: + return @(defaultValue_.valueUInt64); + case GPBTypeData: + // Like message fields, the default is zero length data. + return (defaultValue_.valueData ? defaultValue_.valueData + : GPBEmptyNSData()); + case GPBTypeString: + // Like message fields, the default is zero length string. + return (defaultValue_.valueString ? defaultValue_.valueString : @""); + case GPBTypeGroup: + case GPBTypeMessage: + NSAssert(0, @"Shouldn't get here"); + return nil; + } +} + +#pragma mark Internals + +- (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input + extensionRegistry:(GPBExtensionRegistry *)extensionRegistry + message:(GPBMessage *)message { + GPBCodedInputStreamState *state = &input->state_; + if (ExtensionIsPacked(description_)) { + int32_t length = GPBCodedInputStreamReadInt32(state); + size_t limit = GPBCodedInputStreamPushLimit(state, length); + while (GPBCodedInputStreamBytesUntilLimit(state) > 0) { + id value = [self newSingleValueFromCodedInputStream:input + extensionRegistry:extensionRegistry + existingValue:nil]; + [message addExtension:self value:value]; + [value release]; + } + GPBCodedInputStreamPopLimit(state, limit); + } else { + id existingValue = nil; + BOOL isRepeated = ExtensionIsRepeated(description_); + if (!isRepeated && GPBTypeIsMessage(description_->type)) { + existingValue = [message getExistingExtension:self]; + } + id value = [self newSingleValueFromCodedInputStream:input + extensionRegistry:extensionRegistry + existingValue:existingValue]; + if (isRepeated) { + [message addExtension:self value:value]; + } else { + [message setExtension:self value:value]; + } + [value release]; + } +} + +- (void)writeValue:(id)value + includingTagToCodedOutputStream:(GPBCodedOutputStream *)output { + if (ExtensionIsRepeated(description_)) { + WriteArrayIncludingTagsToCodedOutputStream(value, description_, output); + } else { + WriteObjectIncludingTagToCodedOutputStream(value, description_, output); + } +} + +- (size_t)computeSerializedSizeIncludingTag:(id)value { + if (ExtensionIsRepeated(description_)) { + return ComputeSerializedSizeIncludingTagOfArray(description_, value); + } else { + return ComputeSerializedSizeIncludingTagOfObject(description_, value); + } +} + +// Note that this returns a retained value intentionally. +- (id)newSingleValueFromCodedInputStream:(GPBCodedInputStream *)input + extensionRegistry:(GPBExtensionRegistry *)extensionRegistry + existingValue:(GPBMessage *)existingValue { + GPBCodedInputStreamState *state = &input->state_; + switch (description_->type) { + case GPBTypeBool: return [[NSNumber alloc] initWithBool:GPBCodedInputStreamReadBool(state)]; + case GPBTypeFixed32: return [[NSNumber alloc] initWithUnsignedInt:GPBCodedInputStreamReadFixed32(state)]; + case GPBTypeSFixed32: return [[NSNumber alloc] initWithInt:GPBCodedInputStreamReadSFixed32(state)]; + case GPBTypeFloat: return [[NSNumber alloc] initWithFloat:GPBCodedInputStreamReadFloat(state)]; + case GPBTypeFixed64: return [[NSNumber alloc] initWithUnsignedLongLong:GPBCodedInputStreamReadFixed64(state)]; + case GPBTypeSFixed64: return [[NSNumber alloc] initWithLongLong:GPBCodedInputStreamReadSFixed64(state)]; + case GPBTypeDouble: return [[NSNumber alloc] initWithDouble:GPBCodedInputStreamReadDouble(state)]; + case GPBTypeInt32: return [[NSNumber alloc] initWithInt:GPBCodedInputStreamReadInt32(state)]; + case GPBTypeInt64: return [[NSNumber alloc] initWithLongLong:GPBCodedInputStreamReadInt64(state)]; + case GPBTypeSInt32: return [[NSNumber alloc] initWithInt:GPBCodedInputStreamReadSInt32(state)]; + case GPBTypeSInt64: return [[NSNumber alloc] initWithLongLong:GPBCodedInputStreamReadSInt64(state)]; + case GPBTypeUInt32: return [[NSNumber alloc] initWithUnsignedInt:GPBCodedInputStreamReadUInt32(state)]; + case GPBTypeUInt64: return [[NSNumber alloc] initWithUnsignedLongLong:GPBCodedInputStreamReadUInt64(state)]; + case GPBTypeData: return GPBCodedInputStreamReadRetainedData(state); + case GPBTypeString: return GPBCodedInputStreamReadRetainedString(state); + case GPBTypeEnum: return [[NSNumber alloc] initWithInt:GPBCodedInputStreamReadEnum(state)]; + case GPBTypeGroup: + case GPBTypeMessage: { + GPBMessage *message; + if (existingValue) { + message = [existingValue retain]; + } else { + GPBDescriptor *decriptor = [descriptor_.msgClass descriptor]; + message = [[decriptor.messageClass alloc] init]; + } + + if (description_->type == GPBTypeGroup) { + [input readGroup:description_->fieldNumber + message:message + extensionRegistry:extensionRegistry]; + } else { + // description_->type == GPBTypeMessage + if (ExtensionIsWireFormat(description_)) { + // For MessageSet fields the message length will have already been + // read. + [message mergeFromCodedInputStream:input + extensionRegistry:extensionRegistry]; + } else { + [input readMessage:message extensionRegistry:extensionRegistry]; + } + } + + return message; + } + } + + return nil; +} + +- (NSComparisonResult)compareByFieldNumber:(GPBExtensionField *)other { + int32_t selfNumber = description_->fieldNumber; + int32_t otherNumber = other->description_->fieldNumber; + if (selfNumber < otherNumber) { + return NSOrderedAscending; + } else if (selfNumber == otherNumber) { + return NSOrderedSame; + } else { + return NSOrderedDescending; + } +} + +@end diff --git a/objectivec/GPBExtensionField_PackagePrivate.h b/objectivec/GPBExtensionField_PackagePrivate.h new file mode 100644 index 00000000..6256b9a7 --- /dev/null +++ b/objectivec/GPBExtensionField_PackagePrivate.h @@ -0,0 +1,51 @@ +// 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. + +#import <Foundation/Foundation.h> + +#import "GPBExtensionField.h" + +struct GPBExtensionDescription; + +@interface GPBExtensionField () + +- (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input + extensionRegistry:(GPBExtensionRegistry *)extensionRegistry + message:(GPBMessage *)message; + +- (instancetype)initWithDescription:(struct GPBExtensionDescription *)description; + +- (size_t)computeSerializedSizeIncludingTag:(id)value; +- (void)writeValue:(id)value + includingTagToCodedOutputStream:(GPBCodedOutputStream *)output; + +- (NSComparisonResult)compareByFieldNumber:(GPBExtensionField *)other; + +@end diff --git a/objectivec/GPBExtensionRegistry.h b/objectivec/GPBExtensionRegistry.h new file mode 100644 index 00000000..ce1f8fab --- /dev/null +++ b/objectivec/GPBExtensionRegistry.h @@ -0,0 +1,46 @@ +// 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. + +#import <Foundation/Foundation.h> + +@class GPBDescriptor; +@class GPBExtensionField; + +// A table of known extensions, searchable by name or field number. When +// parsing a protocol message that might have extensions, you must provide an +// ExtensionRegistry in which you have registered any extensions that you want +// to be able to parse. Otherwise, those extensions will just be treated like +// unknown fields. +@interface GPBExtensionRegistry : NSObject + +- (GPBExtensionField *)getExtension:(GPBDescriptor *)containingType + fieldNumber:(NSInteger)fieldNumber; + +@end diff --git a/objectivec/GPBExtensionRegistry.m b/objectivec/GPBExtensionRegistry.m new file mode 100644 index 00000000..a191dace --- /dev/null +++ b/objectivec/GPBExtensionRegistry.m @@ -0,0 +1,98 @@ +// 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. + +#import "GPBExtensionRegistry_PackagePrivate.h" + +#import "GPBBootstrap.h" +#import "GPBDescriptor.h" +#import "GPBExtensionField.h" + +@implementation GPBExtensionRegistry { + // TODO(dmaclach): Reimplement with CFDictionaries that don't use + // objects as keys. + NSMutableDictionary *mutableClassMap_; +} + +- (instancetype)init { + if ((self = [super init])) { + mutableClassMap_ = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)dealloc { + [mutableClassMap_ release]; + [super dealloc]; +} + +- (NSMutableDictionary *)extensionMapForContainingType: + (GPBDescriptor *)containingType { + NSMutableDictionary *extensionMap = + [mutableClassMap_ objectForKey:containingType]; + if (extensionMap == nil) { + extensionMap = [NSMutableDictionary dictionary]; + [mutableClassMap_ setObject:extensionMap forKey:containingType]; + } + return extensionMap; +} + +- (void)addExtension:(GPBExtensionField *)extension { + if (extension == nil) { + return; + } + + GPBDescriptor *containingType = [extension containingType]; + NSMutableDictionary *extensionMap = + [self extensionMapForContainingType:containingType]; + [extensionMap setObject:extension forKey:@([extension fieldNumber])]; +} + +- (GPBExtensionField *)getExtension:(GPBDescriptor *)containingType + fieldNumber:(NSInteger)fieldNumber { + NSDictionary *extensionMap = [mutableClassMap_ objectForKey:containingType]; + return [extensionMap objectForKey:@(fieldNumber)]; +} + +- (void)addExtensions:(GPBExtensionRegistry *)registry { + if (registry == nil) { + // In the case where there are no extensions just ignore. + return; + } + NSMutableDictionary *otherClassMap = registry->mutableClassMap_; + for (GPBDescriptor *containingType in otherClassMap) { + NSMutableDictionary *extensionMap = + [self extensionMapForContainingType:containingType]; + NSMutableDictionary *otherExtensionMap = + [registry extensionMapForContainingType:containingType]; + [extensionMap addEntriesFromDictionary:otherExtensionMap]; + } +} + +@end diff --git a/objectivec/GPBExtensionRegistry_PackagePrivate.h b/objectivec/GPBExtensionRegistry_PackagePrivate.h new file mode 100644 index 00000000..968cb1fd --- /dev/null +++ b/objectivec/GPBExtensionRegistry_PackagePrivate.h @@ -0,0 +1,40 @@ +// 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. + +#import <Foundation/Foundation.h> + +#import "GPBExtensionRegistry.h" + +@interface GPBExtensionRegistry () + +- (void)addExtension:(GPBExtensionField *)extension; +- (void)addExtensions:(GPBExtensionRegistry *)registry; + +@end diff --git a/objectivec/GPBField.h b/objectivec/GPBField.h new file mode 100644 index 00000000..041a242f --- /dev/null +++ b/objectivec/GPBField.h @@ -0,0 +1,56 @@ +// 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. + +#import <Foundation/Foundation.h> + +@class GPBCodedOutputStream; +@class GPBUInt32Array; +@class GPBUInt64Array; +@class GPBUnknownFieldSet; + +@interface GPBField : NSObject<NSCopying> + +@property(nonatomic, readonly, assign) int32_t number; + +// Only one of these will be set. +@property(nonatomic, readonly, strong) GPBUInt64Array *varintList; +@property(nonatomic, readonly, strong) GPBUInt32Array *fixed32List; +@property(nonatomic, readonly, strong) GPBUInt64Array *fixed64List; +@property(nonatomic, readonly, strong) NSArray *lengthDelimitedList; +@property(nonatomic, readonly, strong) NSArray *groupList; + +// Only one of these should be used per Field. +- (void)addVarint:(uint64_t)value; +- (void)addFixed32:(uint32_t)value; +- (void)addFixed64:(uint64_t)value; +- (void)addLengthDelimited:(NSData *)value; +- (void)addGroup:(GPBUnknownFieldSet *)value; + +@end diff --git a/objectivec/GPBField.m b/objectivec/GPBField.m new file mode 100644 index 00000000..c390ae9e --- /dev/null +++ b/objectivec/GPBField.m @@ -0,0 +1,328 @@ +// 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. + +#import "GPBField_PackagePrivate.h" + +#import "GPBArray.h" +#import "GPBCodedOutputStream.h" + +@interface GPBField () { + @protected + int32_t number_; + GPBUInt64Array *mutableVarintList_; + GPBUInt32Array *mutableFixed32List_; + GPBUInt64Array *mutableFixed64List_; + NSMutableArray *mutableLengthDelimitedList_; + NSMutableArray *mutableGroupList_; +} +@end + +@implementation GPBField + +@synthesize number = number_; +@synthesize varintList = mutableVarintList_; +@synthesize fixed32List = mutableFixed32List_; +@synthesize fixed64List = mutableFixed64List_; +@synthesize lengthDelimitedList = mutableLengthDelimitedList_; +@synthesize groupList = mutableGroupList_; + +- (instancetype)initWithNumber:(int32_t)number { + if ((self = [super init])) { + number_ = number; + } + return self; +} + +- (void)dealloc { + [mutableVarintList_ release]; + [mutableFixed32List_ release]; + [mutableFixed64List_ release]; + [mutableLengthDelimitedList_ release]; + [mutableGroupList_ release]; + + [super dealloc]; +} + +- (id)copyWithZone:(NSZone *)zone { + GPBField *result = [[GPBField allocWithZone:zone] initWithNumber:number_]; + result->mutableFixed32List_ = [mutableFixed32List_ copyWithZone:zone]; + result->mutableFixed64List_ = [mutableFixed64List_ copyWithZone:zone]; + result->mutableLengthDelimitedList_ = + [mutableLengthDelimitedList_ copyWithZone:zone]; + result->mutableVarintList_ = [mutableVarintList_ copyWithZone:zone]; + if (mutableGroupList_.count) { + result->mutableGroupList_ = [[NSMutableArray allocWithZone:zone] + initWithCapacity:mutableGroupList_.count]; + for (GPBUnknownFieldSet *group in mutableGroupList_) { + GPBUnknownFieldSet *copied = [group copyWithZone:zone]; + [result->mutableGroupList_ addObject:copied]; + [copied release]; + } + } + return result; +} + +- (BOOL)isEqual:(id)object { + if (self == object) return YES; + if (![object isKindOfClass:[GPBField class]]) return NO; + GPBField *field = (GPBField *)object; + BOOL equalVarint = + (mutableVarintList_.count == 0 && field->mutableVarintList_.count == 0) || + [mutableVarintList_ isEqual:field->mutableVarintList_]; + if (!equalVarint) return NO; + BOOL equalFixed32 = (mutableFixed32List_.count == 0 && + field->mutableFixed32List_.count == 0) || + [mutableFixed32List_ isEqual:field->mutableFixed32List_]; + if (!equalFixed32) return NO; + BOOL equalFixed64 = (mutableFixed64List_.count == 0 && + field->mutableFixed64List_.count == 0) || + [mutableFixed64List_ isEqual:field->mutableFixed64List_]; + if (!equalFixed64) return NO; + BOOL equalLDList = + (mutableLengthDelimitedList_.count == 0 && + field->mutableLengthDelimitedList_.count == 0) || + [mutableLengthDelimitedList_ isEqual:field->mutableLengthDelimitedList_]; + if (!equalLDList) return NO; + BOOL equalGroupList = + (mutableGroupList_.count == 0 && field->mutableGroupList_.count == 0) || + [mutableGroupList_ isEqual:field->mutableGroupList_]; + if (!equalGroupList) return NO; + return YES; +} + +- (NSUInteger)hash { + // Just mix the hashes of the possible sub arrays. + const int prime = 31; + NSUInteger result = prime + [mutableVarintList_ hash]; + result = prime * result + [mutableFixed32List_ hash]; + result = prime * result + [mutableFixed64List_ hash]; + result = prime * result + [mutableLengthDelimitedList_ hash]; + result = prime * result + [mutableGroupList_ hash]; + return result; +} + +- (void)writeToOutput:(GPBCodedOutputStream *)output { + NSUInteger count = mutableVarintList_.count; + if (count > 0) { + [output writeUInt64s:number_ values:mutableVarintList_ tag:0]; + } + count = mutableFixed32List_.count; + if (count > 0) { + [output writeFixed32s:number_ values:mutableFixed32List_ tag:0]; + } + count = mutableFixed64List_.count; + if (count > 0) { + [output writeFixed64s:number_ values:mutableFixed64List_ tag:0]; + } + count = mutableLengthDelimitedList_.count; + if (count > 0) { + [output writeDatas:number_ values:mutableLengthDelimitedList_]; + } + count = mutableGroupList_.count; + if (count > 0) { + [output writeUnknownGroups:number_ values:mutableGroupList_]; + } +} + +- (size_t)serializedSize { + __block size_t result = 0; + int32_t number = number_; + [mutableVarintList_ + enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + result += GPBComputeUInt64Size(number, value); + }]; + + [mutableFixed32List_ + enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + result += GPBComputeFixed32Size(number, value); + }]; + + [mutableFixed64List_ + enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + result += GPBComputeFixed64Size(number, value); + }]; + + for (NSData *data in mutableLengthDelimitedList_) { + result += GPBComputeDataSize(number, data); + } + + for (GPBUnknownFieldSet *set in mutableGroupList_) { + result += GPBComputeUnknownGroupSize(number, set); + } + + return result; +} + +- (void)writeAsMessageSetExtensionToOutput:(GPBCodedOutputStream *)output { + for (NSData *data in mutableLengthDelimitedList_) { + [output writeRawMessageSetExtension:number_ value:data]; + } +} + +- (size_t)serializedSizeAsMessageSetExtension { + size_t result = 0; + for (NSData *data in mutableLengthDelimitedList_) { + result += GPBComputeRawMessageSetExtensionSize(number_, data); + } + return result; +} + +- (NSString *)description { + NSMutableString *description = [NSMutableString + stringWithFormat:@"<%@ %p>: Field: %d {\n", [self class], self, number_]; + [mutableVarintList_ + enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [description appendFormat:@"\t%llu\n", value]; + }]; + + [mutableFixed32List_ + enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [description appendFormat:@"\t%u\n", value]; + }]; + + [mutableFixed64List_ + enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { +#pragma unused(idx, stop) + [description appendFormat:@"\t%llu\n", value]; + }]; + + for (NSData *data in mutableLengthDelimitedList_) { + [description appendFormat:@"\t%@\n", data]; + } + + for (GPBUnknownFieldSet *set in mutableGroupList_) { + [description appendFormat:@"\t%@\n", set]; + } + [description appendString:@"}"]; + return description; +} + +- (void)mergeFromField:(GPBField *)other { + GPBUInt64Array *otherVarintList = other.varintList; + if (otherVarintList.count > 0) { + if (mutableVarintList_ == nil) { + mutableVarintList_ = [otherVarintList copy]; + } else { + [mutableVarintList_ addValuesFromArray:otherVarintList]; + } + } + + GPBUInt32Array *otherFixed32List = other.fixed32List; + if (otherFixed32List.count > 0) { + if (mutableFixed32List_ == nil) { + mutableFixed32List_ = [otherFixed32List copy]; + } else { + [mutableFixed32List_ addValuesFromArray:otherFixed32List]; + } + } + + GPBUInt64Array *otherFixed64List = other.fixed64List; + if (otherFixed64List.count > 0) { + if (mutableFixed64List_ == nil) { + mutableFixed64List_ = [otherFixed64List copy]; + } else { + [mutableFixed64List_ addValuesFromArray:otherFixed64List]; + } + } + + NSArray *otherLengthDelimitedList = other.lengthDelimitedList; + if (otherLengthDelimitedList.count > 0) { + if (mutableLengthDelimitedList_ == nil) { + mutableLengthDelimitedList_ = [otherLengthDelimitedList mutableCopy]; + } else { + [mutableLengthDelimitedList_ + addObjectsFromArray:otherLengthDelimitedList]; + } + } + + NSArray *otherGroupList = other.groupList; + if (otherGroupList.count > 0) { + if (mutableGroupList_ == nil) { + mutableGroupList_ = + [[NSMutableArray alloc] initWithCapacity:otherGroupList.count]; + } + // Make our own mutable copies. + for (GPBUnknownFieldSet *group in otherGroupList) { + GPBUnknownFieldSet *copied = [group copy]; + [mutableGroupList_ addObject:copied]; + [copied release]; + } + } +} + +- (void)addVarint:(uint64_t)value { + if (mutableVarintList_ == nil) { + mutableVarintList_ = [[GPBUInt64Array alloc] initWithValues:&value count:1]; + } else { + [mutableVarintList_ addValue:value]; + } +} + +- (void)addFixed32:(uint32_t)value { + if (mutableFixed32List_ == nil) { + mutableFixed32List_ = + [[GPBUInt32Array alloc] initWithValues:&value count:1]; + } else { + [mutableFixed32List_ addValue:value]; + } +} + +- (void)addFixed64:(uint64_t)value { + if (mutableFixed64List_ == nil) { + mutableFixed64List_ = + [[GPBUInt64Array alloc] initWithValues:&value count:1]; + } else { + [mutableFixed64List_ addValue:value]; + } +} + +- (void)addLengthDelimited:(NSData *)value { + if (mutableLengthDelimitedList_ == nil) { + mutableLengthDelimitedList_ = + [[NSMutableArray alloc] initWithObjects:&value count:1]; + } else { + [mutableLengthDelimitedList_ addObject:value]; + } +} + +- (void)addGroup:(GPBUnknownFieldSet *)value { + if (mutableGroupList_ == nil) { + mutableGroupList_ = [[NSMutableArray alloc] initWithObjects:&value count:1]; + } else { + [mutableGroupList_ addObject:value]; + } +} + +@end diff --git a/objectivec/GPBField_PackagePrivate.h b/objectivec/GPBField_PackagePrivate.h new file mode 100644 index 00000000..73c1fa80 --- /dev/null +++ b/objectivec/GPBField_PackagePrivate.h @@ -0,0 +1,49 @@ +// 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. + +#import <Foundation/Foundation.h> + +#import "GPBField.h" + +@class GPBCodedOutputStream; + +@interface GPBField () + +- (instancetype)initWithNumber:(int32_t)number; + +- (void)writeToOutput:(GPBCodedOutputStream *)output; +- (size_t)serializedSize; + +- (void)writeAsMessageSetExtensionToOutput:(GPBCodedOutputStream *)output; +- (size_t)serializedSizeAsMessageSetExtension; + +- (void)mergeFromField:(GPBField *)other; + +@end diff --git a/objectivec/GPBMessage.h b/objectivec/GPBMessage.h new file mode 100644 index 00000000..2483f5d3 --- /dev/null +++ b/objectivec/GPBMessage.h @@ -0,0 +1,151 @@ +// 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. + +#import "GPBRootObject.h" + +@class GPBDescriptor; +@class GPBCodedInputStream; +@class GPBCodedOutputStream; +@class GPBExtensionField; +@class GPBFieldDescriptor; +@class GPBUnknownFieldSet; + +// In DEBUG ONLY, an NSException is thrown when a parsed message doesn't +// contain required fields. This key allows you to retrieve the parsed message +// from the exception's |userInfo| dictionary. +#ifdef DEBUG +extern NSString *const GPBExceptionMessageKey; +#endif // DEBUG + +// NOTE: +// If you add a instance method/property to this class that may conflict with +// methods declared in protos, you need to update objective_helpers.cc. +// The main cases are methods that take no arguments, or setFoo:/hasFoo: type +// methods. +@interface GPBMessage : GPBRootObject<NSCoding, NSCopying> + +@property(nonatomic, readonly) GPBUnknownFieldSet *unknownFields; + +// Are all required fields in the message and all embedded messages set. +@property(nonatomic, readonly, getter=isInitialized) BOOL initialized; + +// Returns an autoreleased instance. ++ (instancetype)message; + +// Create a message based on a variety of inputs. +// In DEBUG ONLY +// @throws NSInternalInconsistencyException The message is missing one or more +// required fields (i.e. -[isInitialized] returns false). Use +// GGPBExceptionMessageKey to retrieve the message from |userInfo|. ++ (instancetype)parseFromData:(NSData *)data; ++ (instancetype)parseFromData:(NSData *)data + extensionRegistry:(GPBExtensionRegistry *)extensionRegistry; ++ (instancetype)parseFromCodedInputStream:(GPBCodedInputStream *)input + extensionRegistry: + (GPBExtensionRegistry *)extensionRegistry; + +// Create a message based on delimited input. ++ (instancetype)parseDelimitedFromCodedInputStream:(GPBCodedInputStream *)input + extensionRegistry: + (GPBExtensionRegistry *)extensionRegistry; + +- (instancetype)initWithData:(NSData *)data; +- (instancetype)initWithData:(NSData *)data + extensionRegistry:(GPBExtensionRegistry *)extensionRegistry; +- (instancetype)initWithCodedInputStream:(GPBCodedInputStream *)input + extensionRegistry: + (GPBExtensionRegistry *)extensionRegistry; + +// Serializes the message and writes it to output. +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output; +- (void)writeToOutputStream:(NSOutputStream *)output; + +// Serializes the message and writes it to output, but writes the size of the +// message as a variant before writing the message. +- (void)writeDelimitedToCodedOutputStream:(GPBCodedOutputStream *)output; +- (void)writeDelimitedToOutputStream:(NSOutputStream *)output; + +// Serializes the message to an NSData. Note that this value is not cached, so +// if you are using it repeatedly, cache it yourself. +// In DEBUG ONLY: +// @throws NSInternalInconsistencyException The message is missing one or more +// required fields (i.e. -[isInitialized] returns false). Use +// GPBExceptionMessageKey to retrieve the message from |userInfo|. +- (NSData *)data; + +// Same as -[data], except a delimiter is added to the start of the data +// indicating the size of the message data that follows. +- (NSData *)delimitedData; + +// Returns the size of the object if it were serialized. +// This is not a cached value. If you are following a pattern like this: +// size_t size = [aMsg serializedSize]; +// NSMutableData *foo = [NSMutableData dataWithCapacity:size + sizeof(size)]; +// [foo writeSize:size]; +// [foo appendData:[aMsg data]]; +// you would be better doing: +// NSData *data = [aMsg data]; +// NSUInteger size = [aMsg length]; +// NSMutableData *foo = [NSMutableData dataWithCapacity:size + sizeof(size)]; +// [foo writeSize:size]; +// [foo appendData:data]; +- (size_t)serializedSize; + +// Return the descriptor for the message ++ (GPBDescriptor *)descriptor; +- (GPBDescriptor *)descriptor; + +// Extensions use boxed values (NSNumbers) for PODs, NSMutableArrays for +// repeated. If the extension is a Message, just like fields, one will be +// auto created for you and returned. +- (BOOL)hasExtension:(GPBExtensionField *)extension; +- (id)getExtension:(GPBExtensionField *)extension; +- (void)setExtension:(GPBExtensionField *)extension value:(id)value; +- (void)addExtension:(GPBExtensionField *)extension value:(id)value; +- (void)setExtension:(GPBExtensionField *)extension + index:(NSUInteger)index + value:(id)value; +- (void)clearExtension:(GPBExtensionField *)extension; + +- (void)setUnknownFields:(GPBUnknownFieldSet *)unknownFields; + +// Resets all fields to their default values. +- (void)clear; + +// Parses a message of this type from the input and merges it with this +// message. +- (void)mergeFromData:(NSData *)data + extensionRegistry:(GPBExtensionRegistry *)extensionRegistry; + +// Merges the fields from another message (of the same type) into this +// message. +- (void)mergeFrom:(GPBMessage *)other; + +@end diff --git a/objectivec/GPBMessage.m b/objectivec/GPBMessage.m new file mode 100644 index 00000000..63ffc3bc --- /dev/null +++ b/objectivec/GPBMessage.m @@ -0,0 +1,4735 @@ +// 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. + +#import "GPBMessage_PackagePrivate.h" + +#import <objc/runtime.h> +#import <objc/message.h> + +#import "GPBArray_PackagePrivate.h" +#import "GPBCodedInputStream_PackagePrivate.h" +#import "GPBCodedOutputStream.h" +#import "GPBDescriptor_PackagePrivate.h" +#import "GPBDictionary_PackagePrivate.h" +#import "GPBExtensionField_PackagePrivate.h" +#import "GPBExtensionRegistry_PackagePrivate.h" +#import "GPBUnknownFieldSet_PackagePrivate.h" +#import "GPBUtilities_PackagePrivate.h" + +#ifdef DEBUG +NSString *const GPBExceptionMessageKey = + GPBNSStringifySymbol(GPBExceptionMessage); +#endif // DEBUG + +// +// PLEASE REMEMBER: +// +// This is the base class for *all* messages generated, so any selector defined, +// *public* or *private* could end up colliding with a proto message field. So +// avoid using selectors that could match a property, use C functions to hide +// them, etc. +// + +@interface GPBMessage () { + @package + GPBUnknownFieldSet *unknownFields_; + NSMutableDictionary *extensionMap_; + NSMutableDictionary *autocreatedExtensionMap_; + + // If the object was autocreated, we remember the creator so that if we get + // mutated, we can inform the creator to make our field visible. + GPBMessage *autocreator_; + GPBFieldDescriptor *autocreatorField_; + GPBExtensionField *autocreatorExtension_; +} +@end + +static id CreateArrayForField(GPBFieldDescriptor *field, + GPBMessage *autocreator) + __attribute__((ns_returns_retained)); +static id GetOrCreateArrayIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + GPBFileSyntax syntax); +static id GetArrayIvarWithField(GPBMessage *self, GPBFieldDescriptor *field); +static id GetOrCreateMapIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + GPBFileSyntax syntax); +static NSMutableDictionary *CloneExtensionMap(NSDictionary *extensionMap, + NSZone *zone) + __attribute__((ns_returns_retained)); + +static void CheckExtension(GPBMessage *self, GPBExtensionField *extension) { + if ([[self class] descriptor] != [extension containingType]) { + [NSException + raise:NSInvalidArgumentException + format:@"Extension %@ used on wrong class (%@ instead of %@)", + extension.descriptor.singletonName, + [[self class] descriptor].name, [extension containingType].name]; + } +} + +static NSMutableDictionary *CloneExtensionMap(NSDictionary *extensionMap, + NSZone *zone) { + if (extensionMap.count == 0) { + return nil; + } + NSMutableDictionary *result = [[NSMutableDictionary allocWithZone:zone] + initWithCapacity:extensionMap.count]; + + for (GPBExtensionField *field in extensionMap) { + id value = [extensionMap objectForKey:field]; + GPBExtensionDescriptor *fieldDescriptor = field.descriptor; + BOOL isMessageExtension = GPBExtensionIsMessage(fieldDescriptor); + + if ([field isRepeated]) { + if (isMessageExtension) { + NSMutableArray *list = + [[NSMutableArray alloc] initWithCapacity:[value count]]; + for (GPBMessage *listValue in value) { + GPBMessage *copiedValue = [listValue copyWithZone:zone]; + [list addObject:copiedValue]; + [copiedValue release]; + } + [result setObject:list forKey:field]; + [list release]; + } else { + NSMutableArray *copiedValue = [value mutableCopyWithZone:zone]; + [result setObject:copiedValue forKey:field]; + [copiedValue release]; + } + } else { + if (isMessageExtension) { + GPBMessage *copiedValue = [value copyWithZone:zone]; + [result setObject:copiedValue forKey:field]; + [copiedValue release]; + } else { + [result setObject:value forKey:field]; + } + } + } + + return result; +} + +static id CreateArrayForField(GPBFieldDescriptor *field, + GPBMessage *autocreator) { + id result; + GPBType fieldDataType = GPBGetFieldType(field); + switch (fieldDataType) { + case GPBTypeBool: + result = [[GPBBoolArray alloc] init]; + break; + case GPBTypeFixed32: + case GPBTypeUInt32: + result = [[GPBUInt32Array alloc] init]; + break; + case GPBTypeInt32: + case GPBTypeSFixed32: + case GPBTypeSInt32: + result = [[GPBInt32Array alloc] init]; + break; + case GPBTypeFixed64: + case GPBTypeUInt64: + result = [[GPBUInt64Array alloc] init]; + break; + case GPBTypeInt64: + case GPBTypeSFixed64: + case GPBTypeSInt64: + result = [[GPBInt64Array alloc] init]; + break; + case GPBTypeFloat: + result = [[GPBFloatArray alloc] init]; + break; + case GPBTypeDouble: + result = [[GPBDoubleArray alloc] init]; + break; + + case GPBTypeEnum: + result = [[GPBEnumArray alloc] + initWithValidationFunction:field.enumDescriptor.enumVerifier]; + break; + + case GPBTypeData: + case GPBTypeGroup: + case GPBTypeMessage: + case GPBTypeString: + if (autocreator) { + result = [[GPBAutocreatedArray alloc] init]; + } else { + result = [[NSMutableArray alloc] init]; + } + break; + } + + if (autocreator) { + if (GPBTypeIsObject(fieldDataType)) { + GPBAutocreatedArray *autoArray = result; + autoArray->_autocreator = autocreator; + } else { + GPBInt32Array *gpbArray = result; + gpbArray->_autocreator = autocreator; + } + } + + return result; +} + + +#if !defined(__clang_analyzer__) +// These functions are blocked from the analyzer because the analyzer sees the +// GPBSetRetainedObjectIvarWithFieldInternal() call as consuming the array/map, +// so use of the array/map after the call returns is flagged as a use after +// free. +// But GPBSetRetainedObjectIvarWithFieldInternal() is "consuming" the retain +// count be holding onto the object (it is transfering it), the object is +// still valid after returning from the call. The other way to avoid this +// would be to add a -retain/-autorelease, but that would force every +// repeated/map field parsed into the autorelease pool which is both a memory +// and performance hit. + +static id GetOrCreateArrayIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + GPBFileSyntax syntax) { + id array = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + if (!array) { + // No lock needed, this is called from places expecting to mutate + // so no threading protection is needed. + array = CreateArrayForField(field, nil); + GPBSetRetainedObjectIvarWithFieldInternal(self, field, array, syntax); + } + return array; +} + +// This is like GPBGetObjectIvarWithField(), but for arrays, it should +// only be used to wire the method into the class. +static id GetArrayIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) { + id array = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + if (!array) { + // Check again after getting the lock. + OSSpinLockLock(&self->readOnlyMutex_); + array = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + if (!array) { + array = CreateArrayForField(field, self); + GPBSetAutocreatedRetainedObjectIvarWithField(self, field, array); + } + OSSpinLockUnlock(&self->readOnlyMutex_); + } + return array; +} + +static id GetOrCreateMapIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + GPBFileSyntax syntax) { + id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + if (!dict) { + GPBType keyType = field.mapKeyType; + GPBType valueType = GPBGetFieldType(field); + switch (keyType) { + case GPBTypeBool: + switch (valueType) { + case GPBTypeBool: + dict = [[GPBBoolBoolDictionary alloc] init]; + break; + case GPBTypeFixed32: + case GPBTypeUInt32: + dict = [[GPBBoolUInt32Dictionary alloc] init]; + break; + case GPBTypeInt32: + case GPBTypeSFixed32: + case GPBTypeSInt32: + dict = [[GPBBoolInt32Dictionary alloc] init]; + break; + case GPBTypeFixed64: + case GPBTypeUInt64: + dict = [[GPBBoolUInt64Dictionary alloc] init]; + break; + case GPBTypeInt64: + case GPBTypeSFixed64: + case GPBTypeSInt64: + dict = [[GPBBoolInt64Dictionary alloc] init]; + break; + case GPBTypeFloat: + dict = [[GPBBoolFloatDictionary alloc] init]; + break; + case GPBTypeDouble: + dict = [[GPBBoolDoubleDictionary alloc] init]; + break; + case GPBTypeEnum: + dict = [[GPBBoolEnumDictionary alloc] + initWithValidationFunction:field.enumDescriptor.enumVerifier]; + break; + case GPBTypeData: + case GPBTypeMessage: + case GPBTypeString: + dict = [[GPBBoolObjectDictionary alloc] init]; + break; + case GPBTypeGroup: + NSCAssert(NO, @"shouldn't happen"); + return nil; + } + break; + case GPBTypeFixed32: + case GPBTypeUInt32: + switch (valueType) { + case GPBTypeBool: + dict = [[GPBUInt32BoolDictionary alloc] init]; + break; + case GPBTypeFixed32: + case GPBTypeUInt32: + dict = [[GPBUInt32UInt32Dictionary alloc] init]; + break; + case GPBTypeInt32: + case GPBTypeSFixed32: + case GPBTypeSInt32: + dict = [[GPBUInt32Int32Dictionary alloc] init]; + break; + case GPBTypeFixed64: + case GPBTypeUInt64: + dict = [[GPBUInt32UInt64Dictionary alloc] init]; + break; + case GPBTypeInt64: + case GPBTypeSFixed64: + case GPBTypeSInt64: + dict = [[GPBUInt32Int64Dictionary alloc] init]; + break; + case GPBTypeFloat: + dict = [[GPBUInt32FloatDictionary alloc] init]; + break; + case GPBTypeDouble: + dict = [[GPBUInt32DoubleDictionary alloc] init]; + break; + case GPBTypeEnum: + dict = [[GPBUInt32EnumDictionary alloc] + initWithValidationFunction:field.enumDescriptor.enumVerifier]; + break; + case GPBTypeData: + case GPBTypeMessage: + case GPBTypeString: + dict = [[GPBUInt32ObjectDictionary alloc] init]; + break; + case GPBTypeGroup: + NSCAssert(NO, @"shouldn't happen"); + return nil; + } + break; + case GPBTypeInt32: + case GPBTypeSFixed32: + case GPBTypeSInt32: + switch (valueType) { + case GPBTypeBool: + dict = [[GPBInt32BoolDictionary alloc] init]; + break; + case GPBTypeFixed32: + case GPBTypeUInt32: + dict = [[GPBInt32UInt32Dictionary alloc] init]; + break; + case GPBTypeInt32: + case GPBTypeSFixed32: + case GPBTypeSInt32: + dict = [[GPBInt32Int32Dictionary alloc] init]; + break; + case GPBTypeFixed64: + case GPBTypeUInt64: + dict = [[GPBInt32UInt64Dictionary alloc] init]; + break; + case GPBTypeInt64: + case GPBTypeSFixed64: + case GPBTypeSInt64: + dict = [[GPBInt32Int64Dictionary alloc] init]; + break; + case GPBTypeFloat: + dict = [[GPBInt32FloatDictionary alloc] init]; + break; + case GPBTypeDouble: + dict = [[GPBInt32DoubleDictionary alloc] init]; + break; + case GPBTypeEnum: + dict = [[GPBInt32EnumDictionary alloc] + initWithValidationFunction:field.enumDescriptor.enumVerifier]; + break; + case GPBTypeData: + case GPBTypeMessage: + case GPBTypeString: + dict = [[GPBInt32ObjectDictionary alloc] init]; + break; + case GPBTypeGroup: + NSCAssert(NO, @"shouldn't happen"); + return nil; + } + break; + case GPBTypeFixed64: + case GPBTypeUInt64: + switch (valueType) { + case GPBTypeBool: + dict = [[GPBUInt64BoolDictionary alloc] init]; + break; + case GPBTypeFixed32: + case GPBTypeUInt32: + dict = [[GPBUInt64UInt32Dictionary alloc] init]; + break; + case GPBTypeInt32: + case GPBTypeSFixed32: + case GPBTypeSInt32: + dict = [[GPBUInt64Int32Dictionary alloc] init]; + break; + case GPBTypeFixed64: + case GPBTypeUInt64: + dict = [[GPBUInt64UInt64Dictionary alloc] init]; + break; + case GPBTypeInt64: + case GPBTypeSFixed64: + case GPBTypeSInt64: + dict = [[GPBUInt64Int64Dictionary alloc] init]; + break; + case GPBTypeFloat: + dict = [[GPBUInt64FloatDictionary alloc] init]; + break; + case GPBTypeDouble: + dict = [[GPBUInt64DoubleDictionary alloc] init]; + break; + case GPBTypeEnum: + dict = [[GPBUInt64EnumDictionary alloc] + initWithValidationFunction:field.enumDescriptor.enumVerifier]; + break; + case GPBTypeData: + case GPBTypeMessage: + case GPBTypeString: + dict = [[GPBUInt64ObjectDictionary alloc] init]; + break; + case GPBTypeGroup: + NSCAssert(NO, @"shouldn't happen"); + return nil; + } + break; + case GPBTypeInt64: + case GPBTypeSFixed64: + case GPBTypeSInt64: + switch (valueType) { + case GPBTypeBool: + dict = [[GPBInt64BoolDictionary alloc] init]; + break; + case GPBTypeFixed32: + case GPBTypeUInt32: + dict = [[GPBInt64UInt32Dictionary alloc] init]; + break; + case GPBTypeInt32: + case GPBTypeSFixed32: + case GPBTypeSInt32: + dict = [[GPBInt64Int32Dictionary alloc] init]; + break; + case GPBTypeFixed64: + case GPBTypeUInt64: + dict = [[GPBInt64UInt64Dictionary alloc] init]; + break; + case GPBTypeInt64: + case GPBTypeSFixed64: + case GPBTypeSInt64: + dict = [[GPBInt64Int64Dictionary alloc] init]; + break; + case GPBTypeFloat: + dict = [[GPBInt64FloatDictionary alloc] init]; + break; + case GPBTypeDouble: + dict = [[GPBInt64DoubleDictionary alloc] init]; + break; + case GPBTypeEnum: + dict = [[GPBInt64EnumDictionary alloc] + initWithValidationFunction:field.enumDescriptor.enumVerifier]; + break; + case GPBTypeData: + case GPBTypeMessage: + case GPBTypeString: + dict = [[GPBInt64ObjectDictionary alloc] init]; + break; + case GPBTypeGroup: + NSCAssert(NO, @"shouldn't happen"); + return nil; + } + break; + case GPBTypeString: + switch (valueType) { + case GPBTypeBool: + dict = [[GPBStringBoolDictionary alloc] init]; + break; + case GPBTypeFixed32: + case GPBTypeUInt32: + dict = [[GPBStringUInt32Dictionary alloc] init]; + break; + case GPBTypeInt32: + case GPBTypeSFixed32: + case GPBTypeSInt32: + dict = [[GPBStringInt32Dictionary alloc] init]; + break; + case GPBTypeFixed64: + case GPBTypeUInt64: + dict = [[GPBStringUInt64Dictionary alloc] init]; + break; + case GPBTypeInt64: + case GPBTypeSFixed64: + case GPBTypeSInt64: + dict = [[GPBStringInt64Dictionary alloc] init]; + break; + case GPBTypeFloat: + dict = [[GPBStringFloatDictionary alloc] init]; + break; + case GPBTypeDouble: + dict = [[GPBStringDoubleDictionary alloc] init]; + break; + case GPBTypeEnum: + dict = [[GPBStringEnumDictionary alloc] + initWithValidationFunction:field.enumDescriptor.enumVerifier]; + break; + case GPBTypeData: + case GPBTypeMessage: + case GPBTypeString: + dict = [[NSMutableDictionary alloc] init]; + break; + case GPBTypeGroup: + NSCAssert(NO, @"shouldn't happen"); + return nil; + } + break; + + case GPBTypeFloat: + case GPBTypeDouble: + case GPBTypeEnum: + case GPBTypeData: + case GPBTypeGroup: + case GPBTypeMessage: + NSCAssert(NO, @"shouldn't happen"); + return nil; + } + + GPBSetRetainedObjectIvarWithFieldInternal(self, field, dict, syntax); + } + return dict; +} + +#endif // !defined(__clang_analyzer__) + +GPBMessage *GPBCreateMessageWithAutocreator(Class msgClass, + GPBMessage *autocreator, + GPBFieldDescriptor *field) { + GPBMessage *message = [[msgClass alloc] init]; + message->autocreator_ = autocreator; + message->autocreatorField_ = [field retain]; + return message; +} + +static GPBMessage *CreateMessageWithAutocreatorForExtension( + Class msgClass, GPBMessage *autocreator, GPBExtensionField *extension) + __attribute__((ns_returns_retained)); + +static GPBMessage *CreateMessageWithAutocreatorForExtension( + Class msgClass, GPBMessage *autocreator, GPBExtensionField *extension) { + GPBMessage *message = [[msgClass alloc] init]; + message->autocreator_ = autocreator; + message->autocreatorExtension_ = [extension retain]; + return message; +} + +BOOL GPBWasMessageAutocreatedBy(GPBMessage *message, GPBMessage *parent) { + return (message->autocreator_ == parent); +} + +void GPBBecomeVisibleToAutocreator(GPBMessage *self) { + // Message objects that are implicitly created by accessing a message field + // are initially not visible via the hasX selector. This method makes them + // visible. + if (self->autocreator_) { + // This will recursively make all parent messages visible until it reaches a + // super-creator that's visible. + if (self->autocreatorField_) { + GPBFileSyntax syntax = [self->autocreator_ descriptor].file.syntax; + GPBSetObjectIvarWithFieldInternal(self->autocreator_, + self->autocreatorField_, self, syntax); + } else { + [self->autocreator_ setExtension:self->autocreatorExtension_ value:self]; + } + } +} + +void GPBAutocreatedArrayModified(GPBMessage *self, id array) { + // When one of our autocreated arrays adds elements, make it visible. + GPBDescriptor *descriptor = [[self class] descriptor]; + for (GPBFieldDescriptor *field in descriptor->fields_) { + if (field.fieldType == GPBFieldTypeRepeated) { + id curArray = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + if (curArray == array) { + if (GPBFieldTypeIsObject(field)) { + GPBAutocreatedArray *autoArray = array; + autoArray->_autocreator = nil; + } else { + GPBInt32Array *gpbArray = array; + gpbArray->_autocreator = nil; + } + GPBBecomeVisibleToAutocreator(self); + return; + } + } + } + NSCAssert(NO, @"Unknown array."); +} + +void GPBClearMessageAutocreator(GPBMessage *self) { + if ((self == nil) || !self->autocreator_) { + return; + } + +#if DEBUG && !defined(NS_BLOCK_ASSERTIONS) + // Either the autocreator must have its "has" flag set to YES, or it must be + // NO and not equal to ourselves. + BOOL autocreatorHas = + (self->autocreatorField_ + ? GPBGetHasIvarField(self->autocreator_, self->autocreatorField_) + : [self->autocreator_ hasExtension:self->autocreatorExtension_]); + GPBMessage *autocreatorFieldValue = + (self->autocreatorField_ + ? GPBGetObjectIvarWithFieldNoAutocreate(self->autocreator_, + self->autocreatorField_) + : [self->autocreator_->autocreatedExtensionMap_ + objectForKey:self->autocreatorExtension_]); + NSCAssert(autocreatorHas || autocreatorFieldValue != self, + @"Cannot clear autocreator because it still refers to self."); + +#endif // DEBUG && !defined(NS_BLOCK_ASSERTIONS) + + self->autocreator_ = nil; + [self->autocreatorField_ release]; + self->autocreatorField_ = nil; + [self->autocreatorExtension_ release]; + self->autocreatorExtension_ = nil; +} + +static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) { + if (!self->unknownFields_) { + self->unknownFields_ = [[GPBUnknownFieldSet alloc] init]; + GPBBecomeVisibleToAutocreator(self); + } + return self->unknownFields_; +} + +#ifdef DEBUG +static void DebugRaiseExceptionIfNotInitialized(GPBMessage *message) { + if (!message.initialized) { + NSString *reason = + [NSString stringWithFormat:@"Uninitialized Message %@", message]; + NSDictionary *userInfo = + message ? @{GPBExceptionMessageKey : message} : nil; + NSException *exception = + [NSException exceptionWithName:NSInternalInconsistencyException + reason:reason + userInfo:userInfo]; + [exception raise]; + } +} +#else +GPB_INLINE void DebugRaiseExceptionIfNotInitialized(GPBMessage *message) { +#pragma unused(message) +} +#endif // DEBUG + +@implementation GPBMessage + ++ (void)initialize { + Class pbMessageClass = [GPBMessage class]; + if ([self class] == pbMessageClass) { + // This is here to start up the "base" class descriptor. + [self descriptor]; + } else if ([self superclass] == pbMessageClass) { + // This is here to start up all the "message" subclasses. Just needs to be + // done for the messages, not any of the subclasses. + // This must be done in initialize to enforce thread safety of start up of + // the protocol buffer library. All of the extension registries must be + // created in either "+load" or "+initialize". + [self descriptor]; + [self extensionRegistry]; + } +} + ++ (instancetype)allocWithZone:(NSZone *)zone { + // Override alloc to allocate our classes with the additional storage + // required for the instance variables. + GPBDescriptor *descriptor = [self descriptor]; + return NSAllocateObject(self, descriptor->storageSize_, zone); +} + ++ (instancetype)alloc { + return [self allocWithZone:nil]; +} + ++ (GPBDescriptor *)descriptor { + // This is thread safe because it is called from +initialize. + static GPBDescriptor *descriptor = NULL; + static GPBFileDescriptor *fileDescriptor = NULL; + if (!descriptor) { + // Use a dummy file that marks it as proto2 syntax so when used generically + // it supports unknowns/etc. + fileDescriptor = + [[GPBFileDescriptor alloc] initWithPackage:@"internal" + syntax:GPBFileSyntaxProto2]; + + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBMessage class] + rootClass:Nil + file:fileDescriptor + fields:NULL + fieldCount:0 + oneofs:NULL + oneofCount:0 + enums:NULL + enumCount:0 + ranges:NULL + rangeCount:0 + storageSize:0 + wireFormat:NO]; + } + return descriptor; +} + ++ (instancetype)message { + return [[[self alloc] init] autorelease]; +} + +- (instancetype)init { + if ((self = [super init])) { + messageStorage_ = (GPBMessage_StoragePtr)( + ((uint8_t *)self) + class_getInstanceSize([self class])); + + readOnlyMutex_ = OS_SPINLOCK_INIT; + } + + return self; +} + +- (instancetype)initWithData:(NSData *)data { + return [self initWithData:data extensionRegistry:nil]; +} + +- (instancetype)initWithData:(NSData *)data + extensionRegistry:(GPBExtensionRegistry *)extensionRegistry { + if ((self = [self init])) { + [self mergeFromData:data extensionRegistry:extensionRegistry]; + DebugRaiseExceptionIfNotInitialized(self); + } + return self; +} + +- (instancetype)initWithCodedInputStream:(GPBCodedInputStream *)input + extensionRegistry: + (GPBExtensionRegistry *)extensionRegistry { + if ((self = [self init])) { + [self mergeFromCodedInputStream:input extensionRegistry:extensionRegistry]; + DebugRaiseExceptionIfNotInitialized(self); + } + return self; +} + +- (void)dealloc { + [self internalClear:NO]; + NSCAssert(!autocreator_, @"Autocreator was not cleared before dealloc."); + [super dealloc]; +} + +- (void)copyFieldsInto:(GPBMessage *)message + zone:(NSZone *)zone + descriptor:(GPBDescriptor *)descriptor { + // Copy all the storage... + memcpy(message->messageStorage_, messageStorage_, descriptor->storageSize_); + + GPBFileSyntax syntax = descriptor.file.syntax; + + // Loop over the fields doing fixup... + for (GPBFieldDescriptor *field in descriptor->fields_) { + if (GPBFieldIsMapOrArray(field)) { + id value = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + if (value) { + // We need to copy the array/map, but the catch is for message fields, + // we also need to ensure all the messages as those need copying also. + id newValue; + if (GPBFieldTypeIsMessage(field)) { + if (field.fieldType == GPBFieldTypeRepeated) { + NSArray *existingArray = (NSArray *)value; + NSMutableArray *newArray = + [[NSMutableArray alloc] initWithCapacity:existingArray.count]; + newValue = newArray; + for (GPBMessage *msg in existingArray) { + GPBMessage *copiedMsg = [msg copyWithZone:zone]; + [newArray addObject:copiedMsg]; + [copiedMsg release]; + } + } else { + if (field.mapKeyType == GPBTypeString) { + // Map is an NSDictionary. + NSDictionary *existingDict = value; + NSMutableDictionary *newDict = [[NSMutableDictionary alloc] + initWithCapacity:existingDict.count]; + newValue = newDict; + [existingDict enumerateKeysAndObjectsUsingBlock:^(NSString *key, + GPBMessage *msg, + BOOL *stop) { +#pragma unused(stop) + GPBMessage *copiedMsg = [msg copyWithZone:zone]; + [newDict setObject:copiedMsg forKey:key]; + [copiedMsg release]; + }]; + } else { + // Is one of the GPB*ObjectDictionary classes. Type doesn't + // matter, just need one to invoke the selector. + GPBInt32ObjectDictionary *existingDict = value; + newValue = [existingDict deepCopyWithZone:zone]; + } + } + } else { + // Not messages (but is a map/array)... + if (field.fieldType == GPBFieldTypeRepeated) { + if (GPBFieldTypeIsObject(field)) { + // NSArray + newValue = [value mutableCopyWithZone:zone]; + } else { + // GPB*Array + newValue = [value copyWithZone:zone]; + } + } else { + if (field.mapKeyType == GPBTypeString) { + // NSDictionary + newValue = [value mutableCopyWithZone:zone]; + } else { + // Is one of the GPB*Dictionary classes. Type doesn't matter, + // just need one to invoke the selector. + GPBInt32Int32Dictionary *existingDict = value; + newValue = [existingDict copyWithZone:zone]; + } + } + } + // We retain here because the memcpy picked up the pointer value and + // the next call to SetRetainedObject... will release the current value. + [value retain]; + GPBSetRetainedObjectIvarWithFieldInternal(message, field, newValue, + syntax); + } + } else if (GPBFieldTypeIsMessage(field)) { + // For object types, if we have a value, copy it. If we don't, + // zero it to remove the pointer to something that was autocreated + // (and the ptr just got memcpyed). + if (GPBGetHasIvarField(self, field)) { + GPBMessage *value = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + GPBMessage *newValue = [value copyWithZone:zone]; + // We retain here because the memcpy picked up the pointer value and + // the next call to SetRetainedObject... will release the current value. + [value retain]; + GPBSetRetainedObjectIvarWithFieldInternal(message, field, newValue, + syntax); + } else { + uint8_t *storage = (uint8_t *)message->messageStorage_; + id *typePtr = (id *)&storage[field->description_->offset]; + *typePtr = NULL; + } + } else if (GPBFieldTypeIsObject(field) && GPBGetHasIvarField(self, field)) { + // A set string/data value (message picked off above), copy it. + id value = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + id newValue = [value copyWithZone:zone]; + // We retain here because the memcpy picked up the pointer value and + // the next call to SetRetainedObject... will release the current value. + [value retain]; + GPBSetRetainedObjectIvarWithFieldInternal(message, field, newValue, + syntax); + } else { + // memcpy took care of the rest of the primative fields if they were set. + } + } // for (field in descriptor->fields_) +} + +- (id)copyWithZone:(NSZone *)zone { + GPBDescriptor *descriptor = [self descriptor]; + GPBMessage *result = [[descriptor.messageClass allocWithZone:zone] init]; + + [self copyFieldsInto:result zone:zone descriptor:descriptor]; + // Make immutable copies of the extra bits. + result->unknownFields_ = [unknownFields_ copyWithZone:zone]; + result->extensionMap_ = CloneExtensionMap(extensionMap_, zone); + return result; +} + +- (void)clear { + [self internalClear:YES]; +} + +- (void)internalClear:(BOOL)zeroStorage { + GPBDescriptor *descriptor = [self descriptor]; + for (GPBFieldDescriptor *field in descriptor->fields_) { + if (GPBFieldIsMapOrArray(field)) { + id arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + if (arrayOrMap) { + if (field.fieldType == GPBFieldTypeRepeated) { + if (GPBFieldTypeIsObject(field)) { + GPBAutocreatedArray *autoArray = arrayOrMap; + if (autoArray->_autocreator == self) { + autoArray->_autocreator = nil; + } + } else { + // Type doesn't matter, it is a GPB*Array. + GPBInt32Array *gpbArray = arrayOrMap; + if (gpbArray->_autocreator == self) { + gpbArray->_autocreator = nil; + } + } + } + [arrayOrMap release]; + } + } else if (GPBFieldTypeIsMessage(field)) { + GPBClearAutocreatedMessageIvarWithField(self, field); + GPBMessage *value = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [value release]; + } else if (GPBFieldTypeIsObject(field) && GPBGetHasIvarField(self, field)) { + id value = GPBGetObjectIvarWithField(self, field); + [value release]; + } + } + + // GPBClearMessageAutocreator() expects that its caller has already been + // removed from autocreatedExtensionMap_ so we set to nil first. + NSArray *autocreatedValues = [autocreatedExtensionMap_ allValues]; + [autocreatedExtensionMap_ release]; + autocreatedExtensionMap_ = nil; + + // Since we're clearing all of our extensions, make sure that we clear the + // autocreator on any that we've created so they no longer refer to us. + for (GPBMessage *value in autocreatedValues) { + NSCAssert(GPBWasMessageAutocreatedBy(value, self), + @"Autocreated extension does not refer back to self."); + GPBClearMessageAutocreator(value); + } + + [extensionMap_ release]; + extensionMap_ = nil; + [unknownFields_ release]; + unknownFields_ = nil; + + // Note that clearing does not affect autocreator_. If we are being cleared + // because of a dealloc, then autocreator_ should be nil anyway. If we are + // being cleared because someone explicitly clears us, we don't want to + // sever our relationship with our autocreator. + + if (zeroStorage) { + memset(messageStorage_, 0, descriptor->storageSize_); + } +} + +- (BOOL)isInitialized { + GPBDescriptor *descriptor = [self descriptor]; + for (GPBFieldDescriptor *field in descriptor->fields_) { + if (field.isRequired) { + if (!GPBGetHasIvarField(self, field)) { + return NO; + } + } + if (GPBFieldTypeIsMessage(field)) { + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeSingle) { + if (field.isRequired) { + GPBMessage *message = GPBGetMessageIvarWithField(self, field); + if (!message.initialized) { + return NO; + } + } else { + NSAssert(field.isOptional, + @"If not required or optional, what was it?"); + if (GPBGetHasIvarField(self, field)) { + GPBMessage *message = GPBGetMessageIvarWithField(self, field); + if (!message.initialized) { + return NO; + } + } + } + } else if (fieldType == GPBFieldTypeRepeated) { + NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + for (GPBMessage *message in array) { + if (!message.initialized) { + return NO; + } + } + } else { // fieldType == GPBFieldTypeMap + if (field.mapKeyType == GPBTypeString) { + NSDictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + if (map && !GPBDictionaryIsInitializedInternalHelper(map, field)) { + return NO; + } + } else { + // Real type is GPB*ObjectDictionary, exact type doesn't matter. + GPBInt32ObjectDictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + if (map && ![map isInitialized]) { + return NO; + } + } + } + } + } + + __block BOOL result = YES; + [extensionMap_ + enumerateKeysAndObjectsUsingBlock:^(GPBExtensionField *extension, id obj, + BOOL *stop) { + GPBExtensionDescriptor *extDesc = extension.descriptor; + if (GPBExtensionIsMessage(extDesc)) { + if (extDesc.isRepeated) { + for (GPBMessage *msg in obj) { + if (!msg.initialized) { + result = NO; + *stop = YES; + break; + } + } + } else { + GPBMessage *asMsg = obj; + if (!asMsg.initialized) { + result = NO; + *stop = YES; + } + } + } + }]; + return result; +} + +- (GPBDescriptor *)descriptor { + return [[self class] descriptor]; +} + +- (NSData *)data { + DebugRaiseExceptionIfNotInitialized(self); + NSMutableData *data = [NSMutableData dataWithLength:[self serializedSize]]; + GPBCodedOutputStream *stream = + [[GPBCodedOutputStream alloc] initWithData:data]; + [self writeToCodedOutputStream:stream]; + [stream release]; + return data; +} + +- (NSData *)delimitedData { + size_t serializedSize = [self serializedSize]; + size_t varintSize = GPBComputeRawVarint32SizeForInteger(serializedSize); + NSMutableData *data = + [NSMutableData dataWithLength:(serializedSize + varintSize)]; + GPBCodedOutputStream *stream = + [[GPBCodedOutputStream alloc] initWithData:data]; + [self writeDelimitedToCodedOutputStream:stream]; + [stream release]; + return data; +} + +- (void)writeToOutputStream:(NSOutputStream *)output { + GPBCodedOutputStream *stream = + [[GPBCodedOutputStream alloc] initWithOutputStream:output]; + [self writeToCodedOutputStream:stream]; + [stream release]; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output { + GPBDescriptor *descriptor = [self descriptor]; + NSArray *fieldsArray = descriptor->fields_; + NSUInteger fieldCount = fieldsArray.count; + const GPBExtensionRange *extensionRanges = descriptor.extensionRanges; + NSUInteger extensionRangesCount = descriptor.extensionRangesCount; + for (NSUInteger i = 0, j = 0; i < fieldCount || j < extensionRangesCount;) { + if (i == fieldCount) { + [self writeExtensionsToCodedOutputStream:output + range:extensionRanges[j++]]; + } else if (j == extensionRangesCount || + GPBFieldNumber(fieldsArray[i]) < extensionRanges[j].start) { + [self writeField:fieldsArray[i++] toCodedOutputStream:output]; + } else { + [self writeExtensionsToCodedOutputStream:output + range:extensionRanges[j++]]; + } + } + if (descriptor.isWireFormat) { + [unknownFields_ writeAsMessageSetTo:output]; + } else { + [unknownFields_ writeToCodedOutputStream:output]; + } +} + +- (void)writeDelimitedToOutputStream:(NSOutputStream *)output { + GPBCodedOutputStream *codedOutput = + [[GPBCodedOutputStream alloc] initWithOutputStream:output]; + [self writeDelimitedToCodedOutputStream:codedOutput]; + [codedOutput release]; +} + +- (void)writeDelimitedToCodedOutputStream:(GPBCodedOutputStream *)output { + [output writeRawVarintSizeTAs32:[self serializedSize]]; + [self writeToCodedOutputStream:output]; +} + +- (void)writeField:(GPBFieldDescriptor *)field + toCodedOutputStream:(GPBCodedOutputStream *)output { + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeSingle) { + BOOL has = GPBGetHasIvarField(self, field); + if (!has) { + return; + } + } + uint32_t fieldNumber = GPBFieldNumber(field); + +//%PDDM-DEFINE FIELD_CASE(TYPE, REAL_TYPE) +//%FIELD_CASE_FULL(TYPE, REAL_TYPE, REAL_TYPE) +//%PDDM-DEFINE FIELD_CASE_FULL(TYPE, REAL_TYPE, ARRAY_TYPE) +//% case GPBType##TYPE: +//% if (fieldType == GPBFieldTypeRepeated) { +//% uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; +//% GPB##ARRAY_TYPE##Array *array = +//% GPBGetObjectIvarWithFieldNoAutocreate(self, field); +//% [output write##TYPE##s:fieldNumber values:array tag:tag]; +//% } else if (fieldType == GPBFieldTypeSingle) { +//% [output write##TYPE:fieldNumber +//% TYPE$S value:GPBGet##REAL_TYPE##IvarWithField(self, field)]; +//% } else { // fieldType == GPBFieldTypeMap +//% // Exact type here doesn't matter. +//% GPBInt32##ARRAY_TYPE##Dictionary *dict = +//% GPBGetObjectIvarWithFieldNoAutocreate(self, field); +//% [dict writeToCodedOutputStream:output asField:field]; +//% } +//% break; +//% +//%PDDM-DEFINE FIELD_CASE2(TYPE) +//% case GPBType##TYPE: +//% if (fieldType == GPBFieldTypeRepeated) { +//% NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field); +//% [output write##TYPE##s:fieldNumber values:array]; +//% } else if (fieldType == GPBFieldTypeSingle) { +//% // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check +//% // again. +//% [output write##TYPE:fieldNumber +//% TYPE$S value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)]; +//% } else { // fieldType == GPBFieldTypeMap +//% // Exact type here doesn't matter. +//% id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field); +//% GPBType mapKeyType = field.mapKeyType; +//% if (mapKeyType == GPBTypeString) { +//% GPBDictionaryWriteToStreamInternalHelper(output, dict, field); +//% } else { +//% [dict writeToCodedOutputStream:output asField:field]; +//% } +//% } +//% break; +//% + + switch (GPBGetFieldType(field)) { + +//%PDDM-EXPAND FIELD_CASE(Bool, Bool) +// This block of code is generated, do not edit it directly. + + case GPBTypeBool: + if (fieldType == GPBFieldTypeRepeated) { + uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; + GPBBoolArray *array = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [output writeBools:fieldNumber values:array tag:tag]; + } else if (fieldType == GPBFieldTypeSingle) { + [output writeBool:fieldNumber + value:GPBGetBoolIvarWithField(self, field)]; + } else { // fieldType == GPBFieldTypeMap + // Exact type here doesn't matter. + GPBInt32BoolDictionary *dict = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [dict writeToCodedOutputStream:output asField:field]; + } + break; + +//%PDDM-EXPAND FIELD_CASE(Fixed32, UInt32) +// This block of code is generated, do not edit it directly. + + case GPBTypeFixed32: + if (fieldType == GPBFieldTypeRepeated) { + uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; + GPBUInt32Array *array = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [output writeFixed32s:fieldNumber values:array tag:tag]; + } else if (fieldType == GPBFieldTypeSingle) { + [output writeFixed32:fieldNumber + value:GPBGetUInt32IvarWithField(self, field)]; + } else { // fieldType == GPBFieldTypeMap + // Exact type here doesn't matter. + GPBInt32UInt32Dictionary *dict = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [dict writeToCodedOutputStream:output asField:field]; + } + break; + +//%PDDM-EXPAND FIELD_CASE(SFixed32, Int32) +// This block of code is generated, do not edit it directly. + + case GPBTypeSFixed32: + if (fieldType == GPBFieldTypeRepeated) { + uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; + GPBInt32Array *array = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [output writeSFixed32s:fieldNumber values:array tag:tag]; + } else if (fieldType == GPBFieldTypeSingle) { + [output writeSFixed32:fieldNumber + value:GPBGetInt32IvarWithField(self, field)]; + } else { // fieldType == GPBFieldTypeMap + // Exact type here doesn't matter. + GPBInt32Int32Dictionary *dict = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [dict writeToCodedOutputStream:output asField:field]; + } + break; + +//%PDDM-EXPAND FIELD_CASE(Float, Float) +// This block of code is generated, do not edit it directly. + + case GPBTypeFloat: + if (fieldType == GPBFieldTypeRepeated) { + uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; + GPBFloatArray *array = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [output writeFloats:fieldNumber values:array tag:tag]; + } else if (fieldType == GPBFieldTypeSingle) { + [output writeFloat:fieldNumber + value:GPBGetFloatIvarWithField(self, field)]; + } else { // fieldType == GPBFieldTypeMap + // Exact type here doesn't matter. + GPBInt32FloatDictionary *dict = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [dict writeToCodedOutputStream:output asField:field]; + } + break; + +//%PDDM-EXPAND FIELD_CASE(Fixed64, UInt64) +// This block of code is generated, do not edit it directly. + + case GPBTypeFixed64: + if (fieldType == GPBFieldTypeRepeated) { + uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; + GPBUInt64Array *array = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [output writeFixed64s:fieldNumber values:array tag:tag]; + } else if (fieldType == GPBFieldTypeSingle) { + [output writeFixed64:fieldNumber + value:GPBGetUInt64IvarWithField(self, field)]; + } else { // fieldType == GPBFieldTypeMap + // Exact type here doesn't matter. + GPBInt32UInt64Dictionary *dict = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [dict writeToCodedOutputStream:output asField:field]; + } + break; + +//%PDDM-EXPAND FIELD_CASE(SFixed64, Int64) +// This block of code is generated, do not edit it directly. + + case GPBTypeSFixed64: + if (fieldType == GPBFieldTypeRepeated) { + uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; + GPBInt64Array *array = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [output writeSFixed64s:fieldNumber values:array tag:tag]; + } else if (fieldType == GPBFieldTypeSingle) { + [output writeSFixed64:fieldNumber + value:GPBGetInt64IvarWithField(self, field)]; + } else { // fieldType == GPBFieldTypeMap + // Exact type here doesn't matter. + GPBInt32Int64Dictionary *dict = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [dict writeToCodedOutputStream:output asField:field]; + } + break; + +//%PDDM-EXPAND FIELD_CASE(Double, Double) +// This block of code is generated, do not edit it directly. + + case GPBTypeDouble: + if (fieldType == GPBFieldTypeRepeated) { + uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; + GPBDoubleArray *array = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [output writeDoubles:fieldNumber values:array tag:tag]; + } else if (fieldType == GPBFieldTypeSingle) { + [output writeDouble:fieldNumber + value:GPBGetDoubleIvarWithField(self, field)]; + } else { // fieldType == GPBFieldTypeMap + // Exact type here doesn't matter. + GPBInt32DoubleDictionary *dict = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [dict writeToCodedOutputStream:output asField:field]; + } + break; + +//%PDDM-EXPAND FIELD_CASE(Int32, Int32) +// This block of code is generated, do not edit it directly. + + case GPBTypeInt32: + if (fieldType == GPBFieldTypeRepeated) { + uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; + GPBInt32Array *array = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [output writeInt32s:fieldNumber values:array tag:tag]; + } else if (fieldType == GPBFieldTypeSingle) { + [output writeInt32:fieldNumber + value:GPBGetInt32IvarWithField(self, field)]; + } else { // fieldType == GPBFieldTypeMap + // Exact type here doesn't matter. + GPBInt32Int32Dictionary *dict = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [dict writeToCodedOutputStream:output asField:field]; + } + break; + +//%PDDM-EXPAND FIELD_CASE(Int64, Int64) +// This block of code is generated, do not edit it directly. + + case GPBTypeInt64: + if (fieldType == GPBFieldTypeRepeated) { + uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; + GPBInt64Array *array = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [output writeInt64s:fieldNumber values:array tag:tag]; + } else if (fieldType == GPBFieldTypeSingle) { + [output writeInt64:fieldNumber + value:GPBGetInt64IvarWithField(self, field)]; + } else { // fieldType == GPBFieldTypeMap + // Exact type here doesn't matter. + GPBInt32Int64Dictionary *dict = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [dict writeToCodedOutputStream:output asField:field]; + } + break; + +//%PDDM-EXPAND FIELD_CASE(SInt32, Int32) +// This block of code is generated, do not edit it directly. + + case GPBTypeSInt32: + if (fieldType == GPBFieldTypeRepeated) { + uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; + GPBInt32Array *array = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [output writeSInt32s:fieldNumber values:array tag:tag]; + } else if (fieldType == GPBFieldTypeSingle) { + [output writeSInt32:fieldNumber + value:GPBGetInt32IvarWithField(self, field)]; + } else { // fieldType == GPBFieldTypeMap + // Exact type here doesn't matter. + GPBInt32Int32Dictionary *dict = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [dict writeToCodedOutputStream:output asField:field]; + } + break; + +//%PDDM-EXPAND FIELD_CASE(SInt64, Int64) +// This block of code is generated, do not edit it directly. + + case GPBTypeSInt64: + if (fieldType == GPBFieldTypeRepeated) { + uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; + GPBInt64Array *array = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [output writeSInt64s:fieldNumber values:array tag:tag]; + } else if (fieldType == GPBFieldTypeSingle) { + [output writeSInt64:fieldNumber + value:GPBGetInt64IvarWithField(self, field)]; + } else { // fieldType == GPBFieldTypeMap + // Exact type here doesn't matter. + GPBInt32Int64Dictionary *dict = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [dict writeToCodedOutputStream:output asField:field]; + } + break; + +//%PDDM-EXPAND FIELD_CASE(UInt32, UInt32) +// This block of code is generated, do not edit it directly. + + case GPBTypeUInt32: + if (fieldType == GPBFieldTypeRepeated) { + uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; + GPBUInt32Array *array = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [output writeUInt32s:fieldNumber values:array tag:tag]; + } else if (fieldType == GPBFieldTypeSingle) { + [output writeUInt32:fieldNumber + value:GPBGetUInt32IvarWithField(self, field)]; + } else { // fieldType == GPBFieldTypeMap + // Exact type here doesn't matter. + GPBInt32UInt32Dictionary *dict = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [dict writeToCodedOutputStream:output asField:field]; + } + break; + +//%PDDM-EXPAND FIELD_CASE(UInt64, UInt64) +// This block of code is generated, do not edit it directly. + + case GPBTypeUInt64: + if (fieldType == GPBFieldTypeRepeated) { + uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; + GPBUInt64Array *array = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [output writeUInt64s:fieldNumber values:array tag:tag]; + } else if (fieldType == GPBFieldTypeSingle) { + [output writeUInt64:fieldNumber + value:GPBGetUInt64IvarWithField(self, field)]; + } else { // fieldType == GPBFieldTypeMap + // Exact type here doesn't matter. + GPBInt32UInt64Dictionary *dict = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [dict writeToCodedOutputStream:output asField:field]; + } + break; + +//%PDDM-EXPAND FIELD_CASE_FULL(Enum, Int32, Enum) +// This block of code is generated, do not edit it directly. + + case GPBTypeEnum: + if (fieldType == GPBFieldTypeRepeated) { + uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; + GPBEnumArray *array = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [output writeEnums:fieldNumber values:array tag:tag]; + } else if (fieldType == GPBFieldTypeSingle) { + [output writeEnum:fieldNumber + value:GPBGetInt32IvarWithField(self, field)]; + } else { // fieldType == GPBFieldTypeMap + // Exact type here doesn't matter. + GPBInt32EnumDictionary *dict = + GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [dict writeToCodedOutputStream:output asField:field]; + } + break; + +//%PDDM-EXPAND FIELD_CASE2(Data) +// This block of code is generated, do not edit it directly. + + case GPBTypeData: + if (fieldType == GPBFieldTypeRepeated) { + NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [output writeDatas:fieldNumber values:array]; + } else if (fieldType == GPBFieldTypeSingle) { + // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check + // again. + [output writeData:fieldNumber + value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)]; + } else { // fieldType == GPBFieldTypeMap + // Exact type here doesn't matter. + id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + GPBType mapKeyType = field.mapKeyType; + if (mapKeyType == GPBTypeString) { + GPBDictionaryWriteToStreamInternalHelper(output, dict, field); + } else { + [dict writeToCodedOutputStream:output asField:field]; + } + } + break; + +//%PDDM-EXPAND FIELD_CASE2(String) +// This block of code is generated, do not edit it directly. + + case GPBTypeString: + if (fieldType == GPBFieldTypeRepeated) { + NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [output writeStrings:fieldNumber values:array]; + } else if (fieldType == GPBFieldTypeSingle) { + // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check + // again. + [output writeString:fieldNumber + value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)]; + } else { // fieldType == GPBFieldTypeMap + // Exact type here doesn't matter. + id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + GPBType mapKeyType = field.mapKeyType; + if (mapKeyType == GPBTypeString) { + GPBDictionaryWriteToStreamInternalHelper(output, dict, field); + } else { + [dict writeToCodedOutputStream:output asField:field]; + } + } + break; + +//%PDDM-EXPAND FIELD_CASE2(Message) +// This block of code is generated, do not edit it directly. + + case GPBTypeMessage: + if (fieldType == GPBFieldTypeRepeated) { + NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [output writeMessages:fieldNumber values:array]; + } else if (fieldType == GPBFieldTypeSingle) { + // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check + // again. + [output writeMessage:fieldNumber + value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)]; + } else { // fieldType == GPBFieldTypeMap + // Exact type here doesn't matter. + id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + GPBType mapKeyType = field.mapKeyType; + if (mapKeyType == GPBTypeString) { + GPBDictionaryWriteToStreamInternalHelper(output, dict, field); + } else { + [dict writeToCodedOutputStream:output asField:field]; + } + } + break; + +//%PDDM-EXPAND FIELD_CASE2(Group) +// This block of code is generated, do not edit it directly. + + case GPBTypeGroup: + if (fieldType == GPBFieldTypeRepeated) { + NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + [output writeGroups:fieldNumber values:array]; + } else if (fieldType == GPBFieldTypeSingle) { + // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check + // again. + [output writeGroup:fieldNumber + value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)]; + } else { // fieldType == GPBFieldTypeMap + // Exact type here doesn't matter. + id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + GPBType mapKeyType = field.mapKeyType; + if (mapKeyType == GPBTypeString) { + GPBDictionaryWriteToStreamInternalHelper(output, dict, field); + } else { + [dict writeToCodedOutputStream:output asField:field]; + } + } + break; + +//%PDDM-EXPAND-END (18 expansions) + } +} + +#pragma mark - Extensions + +- (id)getExtension:(GPBExtensionField *)extension { + CheckExtension(self, extension); + id value = [extensionMap_ objectForKey:extension]; + if (value != nil) { + return value; + } + + GPBExtensionDescriptor *extDesc = extension.descriptor; + + // No default for repeated. + if (extDesc.isRepeated) { + return nil; + } + // Non messages get their default. + if (!GPBExtensionIsMessage(extDesc)) { + return [extension defaultValue]; + } + + // Check for an autocreated value. + OSSpinLockLock(&readOnlyMutex_); + value = [autocreatedExtensionMap_ objectForKey:extension]; + if (!value) { + // Auto create the message extensions to match normal fields. + value = CreateMessageWithAutocreatorForExtension(extDesc.msgClass, self, + extension); + + if (autocreatedExtensionMap_ == nil) { + autocreatedExtensionMap_ = [[NSMutableDictionary alloc] init]; + } + + // We can't simply call setExtension here because that would clear the new + // value's autocreator. + [autocreatedExtensionMap_ setObject:value forKey:extension]; + [value release]; + } + + OSSpinLockUnlock(&readOnlyMutex_); + return value; +} + +- (id)getExistingExtension:(GPBExtensionField *)extension { + // This is an internal method so we don't need to call CheckExtension(). + return [extensionMap_ objectForKey:extension]; +} + +- (BOOL)hasExtension:(GPBExtensionField *)extension { +#if DEBUG + CheckExtension(self, extension); +#endif // DEBUG + return nil != [extensionMap_ objectForKey:extension]; +} + +- (NSArray *)extensionsCurrentlySet { + return [extensionMap_ allKeys]; +} + +- (void)writeExtensionsToCodedOutputStream:(GPBCodedOutputStream *)output + range:(GPBExtensionRange)range { + NSArray *sortedExtensions = [[extensionMap_ allKeys] + sortedArrayUsingSelector:@selector(compareByFieldNumber:)]; + uint32_t start = range.start; + uint32_t end = range.end; + for (GPBExtensionField *extension in sortedExtensions) { + uint32_t fieldNumber = [extension fieldNumber]; + if (fieldNumber >= start && fieldNumber < end) { + id value = [extensionMap_ objectForKey:extension]; + [extension writeValue:value includingTagToCodedOutputStream:output]; + } + } +} + +- (NSArray *)sortedExtensionsInUse { + return [[extensionMap_ allKeys] + sortedArrayUsingSelector:@selector(compareByFieldNumber:)]; +} + +- (void)setExtension:(GPBExtensionField *)extension value:(id)value { + if (!value) { + [self clearExtension:extension]; + return; + } + + CheckExtension(self, extension); + + if ([extension isRepeated]) { + [NSException raise:NSInvalidArgumentException + format:@"Must call addExtension() for repeated types."]; + } + + if (extensionMap_ == nil) { + extensionMap_ = [[NSMutableDictionary alloc] init]; + } + + [extensionMap_ setObject:value forKey:extension]; + + GPBExtensionDescriptor *descriptor = extension.descriptor; + + if (GPBExtensionIsMessage(descriptor) && !descriptor.isRepeated) { + GPBMessage *autocreatedValue = + [[autocreatedExtensionMap_ objectForKey:extension] retain]; + // Must remove from the map before calling GPBClearMessageAutocreator() so + // that GPBClearMessageAutocreator() knows its safe to clear. + [autocreatedExtensionMap_ removeObjectForKey:extension]; + GPBClearMessageAutocreator(autocreatedValue); + [autocreatedValue release]; + } + + GPBBecomeVisibleToAutocreator(self); +} + +- (void)addExtension:(GPBExtensionField *)extension value:(id)value { + CheckExtension(self, extension); + + if (![extension isRepeated]) { + [NSException raise:NSInvalidArgumentException + format:@"Must call setExtension() for singular types."]; + } + + if (extensionMap_ == nil) { + extensionMap_ = [[NSMutableDictionary alloc] init]; + } + NSMutableArray *list = [extensionMap_ objectForKey:extension]; + if (list == nil) { + list = [NSMutableArray array]; + [extensionMap_ setObject:list forKey:extension]; + } + + [list addObject:value]; + GPBBecomeVisibleToAutocreator(self); +} + +- (void)setExtension:(GPBExtensionField *)extension + index:(NSUInteger)idx + value:(id)value { + CheckExtension(self, extension); + + if (![extension isRepeated]) { + [NSException raise:NSInvalidArgumentException + format:@"Must call setExtension() for singular types."]; + } + + if (extensionMap_ == nil) { + extensionMap_ = [[NSMutableDictionary alloc] init]; + } + + NSMutableArray *list = [extensionMap_ objectForKey:extension]; + + [list replaceObjectAtIndex:idx withObject:value]; + GPBBecomeVisibleToAutocreator(self); +} + +- (void)clearExtension:(GPBExtensionField *)extension { + CheckExtension(self, extension); + + // Only become visible if there was actually a value to clear. + if ([extensionMap_ objectForKey:extension]) { + [extensionMap_ removeObjectForKey:extension]; + GPBBecomeVisibleToAutocreator(self); + } +} + +#pragma mark - mergeFrom + +- (void)mergeFromData:(NSData *)data + extensionRegistry:(GPBExtensionRegistry *)extensionRegistry { + GPBCodedInputStream *input = [[GPBCodedInputStream alloc] initWithData:data]; + [self mergeFromCodedInputStream:input extensionRegistry:extensionRegistry]; + [input checkLastTagWas:0]; + [input release]; +} + +#pragma mark - mergeDelimitedFrom + +- (void)mergeDelimitedFromCodedInputStream:(GPBCodedInputStream *)input + extensionRegistry:(GPBExtensionRegistry *)extensionRegistry { + GPBCodedInputStreamState *state = &input->state_; + if (GPBCodedInputStreamIsAtEnd(state)) { + return; + } + NSData *data = GPBCodedInputStreamReadRetainedDataNoCopy(state); + if (data == nil) { + return; + } + [self mergeFromData:data extensionRegistry:extensionRegistry]; + [data release]; +} + +#pragma mark - Parse From Data Support + ++ (instancetype)parseFromData:(NSData *)data { + return [self parseFromData:data extensionRegistry:nil]; +} + ++ (instancetype)parseFromData:(NSData *)data + extensionRegistry:(GPBExtensionRegistry *)extensionRegistry { + return [[[self alloc] initWithData:data + extensionRegistry:extensionRegistry] autorelease]; +} + ++ (instancetype)parseFromCodedInputStream:(GPBCodedInputStream *)input + extensionRegistry:(GPBExtensionRegistry *)extensionRegistry { + return + [[[self alloc] initWithCodedInputStream:input + extensionRegistry:extensionRegistry] autorelease]; +} + +#pragma mark - Parse Delimited From Data Support + ++ (instancetype)parseDelimitedFromCodedInputStream:(GPBCodedInputStream *)input + extensionRegistry: + (GPBExtensionRegistry *)extensionRegistry { + GPBMessage *message = [[[self alloc] init] autorelease]; + [message mergeDelimitedFromCodedInputStream:input + extensionRegistry:extensionRegistry]; + DebugRaiseExceptionIfNotInitialized(message); + return message; +} + +#pragma mark - Unknown Field Support + +- (GPBUnknownFieldSet *)unknownFields { + return unknownFields_; +} + +- (void)setUnknownFields:(GPBUnknownFieldSet *)unknownFields { + if (unknownFields != unknownFields_) { + [unknownFields_ release]; + unknownFields_ = [unknownFields copy]; + GPBBecomeVisibleToAutocreator(self); + } +} + +- (void)parseMessageSet:(GPBCodedInputStream *)input + extensionRegistry:(GPBExtensionRegistry *)extensionRegistry { + uint32_t typeId = 0; + NSData *rawBytes = nil; + GPBExtensionField *extension = nil; + GPBCodedInputStreamState *state = &input->state_; + while (true) { + uint32_t tag = GPBCodedInputStreamReadTag(state); + if (tag == 0) { + break; + } + + if (tag == GPBWireFormatMessageSetTypeIdTag) { + typeId = GPBCodedInputStreamReadUInt32(state); + if (typeId != 0) { + extension = [extensionRegistry getExtension:[self descriptor] + fieldNumber:typeId]; + } + } else if (tag == GPBWireFormatMessageSetMessageTag) { + rawBytes = [GPBCodedInputStreamReadRetainedDataNoCopy(state) autorelease]; + } else { + if (![input skipField:tag]) { + break; + } + } + } + + [input checkLastTagWas:GPBWireFormatMessageSetItemEndTag]; + + if (rawBytes != nil && typeId != 0) { + if (extension != nil) { + GPBCodedInputStream *newInput = + [[GPBCodedInputStream alloc] initWithData:rawBytes]; + [extension mergeFromCodedInputStream:newInput + extensionRegistry:extensionRegistry + message:self]; + [newInput release]; + } else { + GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self); + [unknownFields mergeMessageSetMessage:typeId data:rawBytes]; + } + } +} + +- (BOOL)parseUnknownField:(GPBCodedInputStream *)input + extensionRegistry:(GPBExtensionRegistry *)extensionRegistry + tag:(uint32_t)tag { + GPBWireFormat wireType = GPBWireFormatGetTagWireType(tag); + int32_t fieldNumber = GPBWireFormatGetTagFieldNumber(tag); + + GPBDescriptor *descriptor = [self descriptor]; + GPBExtensionField *extension = + [extensionRegistry getExtension:descriptor fieldNumber:fieldNumber]; + + if (extension == nil) { + if (descriptor.wireFormat && GPBWireFormatMessageSetItemTag == tag) { + [self parseMessageSet:input extensionRegistry:extensionRegistry]; + return YES; + } + } else { + if ([extension wireType] == wireType) { + [extension mergeFromCodedInputStream:input + extensionRegistry:extensionRegistry + message:self]; + return YES; + } + } + if ([GPBUnknownFieldSet isFieldTag:tag]) { + GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self); + return [unknownFields mergeFieldFrom:tag input:input]; + } else { + return NO; + } +} + +- (void)addUnknownMapEntry:(int32_t)fieldNum value:(NSData *)data { + GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self); + [unknownFields addUnknownMapEntry:fieldNum value:data]; +} + +#pragma mark - MergeFromCodedInputStream Support + +typedef struct MergeFromCodedInputStreamContext { + GPBMessage *self; + GPBCodedInputStream *stream; + GPBMessage *result; + GPBExtensionRegistry *registry; + uint32_t tag; + GPBFileSyntax syntax; +} MergeFromCodedInputStreamContext; + +//%PDDM-DEFINE MERGE_FROM_CODED_INPUT_STREAM_POD_FUNC(NAME, TYPE, ARRAY_TYPE) +//%static BOOL DynamicMergeFromCodedInputStream##NAME(GPBFieldDescriptor *field, +//% NAME$S void *voidContext) { +//% MergeFromCodedInputStreamContext *context = +//% (MergeFromCodedInputStreamContext *)voidContext; +//% GPBCodedInputStreamState *state = &context->stream->state_; +//% GPBFieldType fieldType = field.fieldType; +//% if (fieldType == GPBFieldTypeRepeated) { +//% GPB##ARRAY_TYPE##Array *array = +//% GetOrCreateArrayIvarWithField(context->result, field, context->syntax); +//% if (field.isPackable) { +//% int32_t length = GPBCodedInputStreamReadInt32(state); +//% size_t limit = GPBCodedInputStreamPushLimit(state, length); +//% while (GPBCodedInputStreamBytesUntilLimit(state) > 0) { +//% TYPE val = GPBCodedInputStreamRead##NAME(state); +//% [array addValue:val]; +//% } +//% GPBCodedInputStreamPopLimit(state, limit); +//% } else { +//% TYPE val = GPBCodedInputStreamRead##NAME(state); +//% [array addValue:val]; +//% } +//% } else if (fieldType == GPBFieldTypeSingle) { +//% TYPE val = GPBCodedInputStreamRead##NAME(state); +//% GPBSet##ARRAY_TYPE##IvarWithFieldInternal(context->result, field, val, +//% ARRAY_TYPE$S context->syntax); +//% } else { // fieldType == GPBFieldTypeMap +//% // The exact type doesn't matter, just need to know it is a GPB*Dictionary. +//% GPBInt32Int32Dictionary *map = +//% GetOrCreateMapIvarWithField(context->result, field, context->syntax); +//% [context->stream readMapEntry:map +//% extensionRegistry:nil +//% field:field +//% parentMessage:context->result]; +//% } +//% return NO; +//%} +//% +//%PDDM-DEFINE MERGE_FROM_CODED_INPUT_STREAM_OBJ_FUNC(NAME) +//%static BOOL DynamicMergeFromCodedInputStream##NAME(GPBFieldDescriptor *field, +//% NAME$S void *voidContext) { +//% MergeFromCodedInputStreamContext *context = voidContext; +//% GPBCodedInputStreamState *state = &context->stream->state_; +//% GPBFieldType fieldType = field.fieldType; +//% if (fieldType == GPBFieldTypeMap) { +//% // GPB*Dictionary or NSDictionary, exact type doesn't matter at this point. +//% id map = +//% GetOrCreateMapIvarWithField(context->result, field, context->syntax); +//% [context->stream readMapEntry:map +//% extensionRegistry:nil +//% field:field +//% parentMessage:context->result]; +//% } else { +//% id val = GPBCodedInputStreamReadRetained##NAME(state); +//% if (fieldType == GPBFieldTypeRepeated) { +//% NSMutableArray *array = +//% GetOrCreateArrayIvarWithField(context->result, field, context->syntax); +//% [array addObject:val]; +//% [val release]; +//% } else { // fieldType == GPBFieldTypeSingle +//% GPBSetRetainedObjectIvarWithFieldInternal(context->result, field, val, +//% context->syntax); +//% } +//% } +//% return NO; +//%} +//% + +static BOOL DynamicMergeFromCodedInputStreamGroup(GPBFieldDescriptor *field, + void *voidContext) { + MergeFromCodedInputStreamContext *context = + (MergeFromCodedInputStreamContext *)voidContext; + int number = GPBFieldNumber(field); + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBMessage *message = [[field.msgClass alloc] init]; + NSMutableArray *array = + GetOrCreateArrayIvarWithField(context->result, field, context->syntax); + [context->stream readGroup:number + message:message + extensionRegistry:context->registry]; + [array addObject:message]; + [message release]; + } else if (fieldType == GPBFieldTypeSingle) { + BOOL has = GPBGetHasIvarField(context->result, field); + if (has) { + // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check + // again. + GPBMessage *message = + GPBGetObjectIvarWithFieldNoAutocreate(context->result, field); + [context->stream readGroup:number + message:message + extensionRegistry:context->registry]; + } else { + GPBMessage *message = [[field.msgClass alloc] init]; + [context->stream readGroup:number + message:message + extensionRegistry:context->registry]; + GPBSetRetainedObjectIvarWithFieldInternal(context->result, field, message, + context->syntax); + } + } else { // fieldType == GPBFieldTypeMap + NSCAssert(NO, @"Shouldn't happen"); + return YES; + } + return NO; +} + +static BOOL DynamicMergeFromCodedInputStreamMessage(GPBFieldDescriptor *field, + void *voidContext) { + MergeFromCodedInputStreamContext *context = + (MergeFromCodedInputStreamContext *)voidContext; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBMessage *message = [[field.msgClass alloc] init]; + NSMutableArray *array = + GetOrCreateArrayIvarWithField(context->result, field, context->syntax); + [context->stream readMessage:message extensionRegistry:context->registry]; + [array addObject:message]; + [message release]; + } else if (fieldType == GPBFieldTypeSingle) { + BOOL has = GPBGetHasIvarField(context->result, field); + if (has) { + // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check + // again. + GPBMessage *message = + GPBGetObjectIvarWithFieldNoAutocreate(context->result, field); + [context->stream readMessage:message extensionRegistry:context->registry]; + } else { + GPBMessage *message = [[field.msgClass alloc] init]; + [context->stream readMessage:message extensionRegistry:context->registry]; + GPBSetRetainedObjectIvarWithFieldInternal(context->result, field, message, + context->syntax); + } + } else { // fieldType == GPBFieldTypeMap + // GPB*Dictionary or NSDictionary, exact type doesn't matter. + id map = + GetOrCreateMapIvarWithField(context->result, field, context->syntax); + [context->stream readMapEntry:map + extensionRegistry:context->registry + field:field + parentMessage:context->result]; + } + return NO; +} + +static BOOL DynamicMergeFromCodedInputStreamEnum(GPBFieldDescriptor *field, + void *voidContext) { + MergeFromCodedInputStreamContext *context = + (MergeFromCodedInputStreamContext *)voidContext; + int number = GPBFieldNumber(field); + BOOL hasPreservingUnknownEnumSemantics = + GPBHasPreservingUnknownEnumSemantics(context->syntax); + GPBCodedInputStreamState *state = &context->stream->state_; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBEnumArray *array = + GetOrCreateArrayIvarWithField(context->result, field, context->syntax); + if (field.isPackable) { + int32_t length = GPBCodedInputStreamReadInt32(state); + size_t limit = GPBCodedInputStreamPushLimit(state, length); + while (GPBCodedInputStreamBytesUntilLimit(state) > 0) { + int32_t val = GPBCodedInputStreamReadEnum(state); + if (hasPreservingUnknownEnumSemantics || [field isValidEnumValue:val]) { + [array addRawValue:val]; + } else { + GPBUnknownFieldSet *unknownFields = + GetOrMakeUnknownFields(context->self); + [unknownFields mergeVarintField:number value:val]; + } + } + GPBCodedInputStreamPopLimit(state, limit); + } else { + int32_t val = GPBCodedInputStreamReadEnum(state); + if (hasPreservingUnknownEnumSemantics || [field isValidEnumValue:val]) { + [array addRawValue:val]; + } else { + GPBUnknownFieldSet *unknownFields = + GetOrMakeUnknownFields(context->self); + [unknownFields mergeVarintField:number value:val]; + } + } + } else if (fieldType == GPBFieldTypeSingle) { + int32_t val = GPBCodedInputStreamReadEnum(state); + if (hasPreservingUnknownEnumSemantics || [field isValidEnumValue:val]) { + GPBSetInt32IvarWithFieldInternal(context->result, field, val, + context->syntax); + } else { + GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(context->self); + [unknownFields mergeVarintField:number value:val]; + } + } else { // fieldType == GPBFieldTypeMap + // The exact type doesn't matter, just need to know it is a + // GPB*EnumDictionary. + GPBInt32EnumDictionary *map = + GetOrCreateMapIvarWithField(context->result, field, context->syntax); + [context->stream readMapEntry:map + extensionRegistry:context->registry + field:field + parentMessage:context->result]; + } + return NO; +} + +//%PDDM-EXPAND MERGE_FROM_CODED_INPUT_STREAM_POD_FUNC(Bool, BOOL, Bool) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicMergeFromCodedInputStreamBool(GPBFieldDescriptor *field, + void *voidContext) { + MergeFromCodedInputStreamContext *context = + (MergeFromCodedInputStreamContext *)voidContext; + GPBCodedInputStreamState *state = &context->stream->state_; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBBoolArray *array = + GetOrCreateArrayIvarWithField(context->result, field, context->syntax); + if (field.isPackable) { + int32_t length = GPBCodedInputStreamReadInt32(state); + size_t limit = GPBCodedInputStreamPushLimit(state, length); + while (GPBCodedInputStreamBytesUntilLimit(state) > 0) { + BOOL val = GPBCodedInputStreamReadBool(state); + [array addValue:val]; + } + GPBCodedInputStreamPopLimit(state, limit); + } else { + BOOL val = GPBCodedInputStreamReadBool(state); + [array addValue:val]; + } + } else if (fieldType == GPBFieldTypeSingle) { + BOOL val = GPBCodedInputStreamReadBool(state); + GPBSetBoolIvarWithFieldInternal(context->result, field, val, + context->syntax); + } else { // fieldType == GPBFieldTypeMap + // The exact type doesn't matter, just need to know it is a GPB*Dictionary. + GPBInt32Int32Dictionary *map = + GetOrCreateMapIvarWithField(context->result, field, context->syntax); + [context->stream readMapEntry:map + extensionRegistry:nil + field:field + parentMessage:context->result]; + } + return NO; +} + +//%PDDM-EXPAND MERGE_FROM_CODED_INPUT_STREAM_POD_FUNC(Int32, int32_t, Int32) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicMergeFromCodedInputStreamInt32(GPBFieldDescriptor *field, + void *voidContext) { + MergeFromCodedInputStreamContext *context = + (MergeFromCodedInputStreamContext *)voidContext; + GPBCodedInputStreamState *state = &context->stream->state_; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBInt32Array *array = + GetOrCreateArrayIvarWithField(context->result, field, context->syntax); + if (field.isPackable) { + int32_t length = GPBCodedInputStreamReadInt32(state); + size_t limit = GPBCodedInputStreamPushLimit(state, length); + while (GPBCodedInputStreamBytesUntilLimit(state) > 0) { + int32_t val = GPBCodedInputStreamReadInt32(state); + [array addValue:val]; + } + GPBCodedInputStreamPopLimit(state, limit); + } else { + int32_t val = GPBCodedInputStreamReadInt32(state); + [array addValue:val]; + } + } else if (fieldType == GPBFieldTypeSingle) { + int32_t val = GPBCodedInputStreamReadInt32(state); + GPBSetInt32IvarWithFieldInternal(context->result, field, val, + context->syntax); + } else { // fieldType == GPBFieldTypeMap + // The exact type doesn't matter, just need to know it is a GPB*Dictionary. + GPBInt32Int32Dictionary *map = + GetOrCreateMapIvarWithField(context->result, field, context->syntax); + [context->stream readMapEntry:map + extensionRegistry:nil + field:field + parentMessage:context->result]; + } + return NO; +} + +//%PDDM-EXPAND MERGE_FROM_CODED_INPUT_STREAM_POD_FUNC(SInt32, int32_t, Int32) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicMergeFromCodedInputStreamSInt32(GPBFieldDescriptor *field, + void *voidContext) { + MergeFromCodedInputStreamContext *context = + (MergeFromCodedInputStreamContext *)voidContext; + GPBCodedInputStreamState *state = &context->stream->state_; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBInt32Array *array = + GetOrCreateArrayIvarWithField(context->result, field, context->syntax); + if (field.isPackable) { + int32_t length = GPBCodedInputStreamReadInt32(state); + size_t limit = GPBCodedInputStreamPushLimit(state, length); + while (GPBCodedInputStreamBytesUntilLimit(state) > 0) { + int32_t val = GPBCodedInputStreamReadSInt32(state); + [array addValue:val]; + } + GPBCodedInputStreamPopLimit(state, limit); + } else { + int32_t val = GPBCodedInputStreamReadSInt32(state); + [array addValue:val]; + } + } else if (fieldType == GPBFieldTypeSingle) { + int32_t val = GPBCodedInputStreamReadSInt32(state); + GPBSetInt32IvarWithFieldInternal(context->result, field, val, + context->syntax); + } else { // fieldType == GPBFieldTypeMap + // The exact type doesn't matter, just need to know it is a GPB*Dictionary. + GPBInt32Int32Dictionary *map = + GetOrCreateMapIvarWithField(context->result, field, context->syntax); + [context->stream readMapEntry:map + extensionRegistry:nil + field:field + parentMessage:context->result]; + } + return NO; +} + +//%PDDM-EXPAND MERGE_FROM_CODED_INPUT_STREAM_POD_FUNC(SFixed32, int32_t, Int32) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicMergeFromCodedInputStreamSFixed32(GPBFieldDescriptor *field, + void *voidContext) { + MergeFromCodedInputStreamContext *context = + (MergeFromCodedInputStreamContext *)voidContext; + GPBCodedInputStreamState *state = &context->stream->state_; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBInt32Array *array = + GetOrCreateArrayIvarWithField(context->result, field, context->syntax); + if (field.isPackable) { + int32_t length = GPBCodedInputStreamReadInt32(state); + size_t limit = GPBCodedInputStreamPushLimit(state, length); + while (GPBCodedInputStreamBytesUntilLimit(state) > 0) { + int32_t val = GPBCodedInputStreamReadSFixed32(state); + [array addValue:val]; + } + GPBCodedInputStreamPopLimit(state, limit); + } else { + int32_t val = GPBCodedInputStreamReadSFixed32(state); + [array addValue:val]; + } + } else if (fieldType == GPBFieldTypeSingle) { + int32_t val = GPBCodedInputStreamReadSFixed32(state); + GPBSetInt32IvarWithFieldInternal(context->result, field, val, + context->syntax); + } else { // fieldType == GPBFieldTypeMap + // The exact type doesn't matter, just need to know it is a GPB*Dictionary. + GPBInt32Int32Dictionary *map = + GetOrCreateMapIvarWithField(context->result, field, context->syntax); + [context->stream readMapEntry:map + extensionRegistry:nil + field:field + parentMessage:context->result]; + } + return NO; +} + +//%PDDM-EXPAND MERGE_FROM_CODED_INPUT_STREAM_POD_FUNC(UInt32, uint32_t, UInt32) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicMergeFromCodedInputStreamUInt32(GPBFieldDescriptor *field, + void *voidContext) { + MergeFromCodedInputStreamContext *context = + (MergeFromCodedInputStreamContext *)voidContext; + GPBCodedInputStreamState *state = &context->stream->state_; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBUInt32Array *array = + GetOrCreateArrayIvarWithField(context->result, field, context->syntax); + if (field.isPackable) { + int32_t length = GPBCodedInputStreamReadInt32(state); + size_t limit = GPBCodedInputStreamPushLimit(state, length); + while (GPBCodedInputStreamBytesUntilLimit(state) > 0) { + uint32_t val = GPBCodedInputStreamReadUInt32(state); + [array addValue:val]; + } + GPBCodedInputStreamPopLimit(state, limit); + } else { + uint32_t val = GPBCodedInputStreamReadUInt32(state); + [array addValue:val]; + } + } else if (fieldType == GPBFieldTypeSingle) { + uint32_t val = GPBCodedInputStreamReadUInt32(state); + GPBSetUInt32IvarWithFieldInternal(context->result, field, val, + context->syntax); + } else { // fieldType == GPBFieldTypeMap + // The exact type doesn't matter, just need to know it is a GPB*Dictionary. + GPBInt32Int32Dictionary *map = + GetOrCreateMapIvarWithField(context->result, field, context->syntax); + [context->stream readMapEntry:map + extensionRegistry:nil + field:field + parentMessage:context->result]; + } + return NO; +} + +//%PDDM-EXPAND MERGE_FROM_CODED_INPUT_STREAM_POD_FUNC(Fixed32, uint32_t, UInt32) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicMergeFromCodedInputStreamFixed32(GPBFieldDescriptor *field, + void *voidContext) { + MergeFromCodedInputStreamContext *context = + (MergeFromCodedInputStreamContext *)voidContext; + GPBCodedInputStreamState *state = &context->stream->state_; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBUInt32Array *array = + GetOrCreateArrayIvarWithField(context->result, field, context->syntax); + if (field.isPackable) { + int32_t length = GPBCodedInputStreamReadInt32(state); + size_t limit = GPBCodedInputStreamPushLimit(state, length); + while (GPBCodedInputStreamBytesUntilLimit(state) > 0) { + uint32_t val = GPBCodedInputStreamReadFixed32(state); + [array addValue:val]; + } + GPBCodedInputStreamPopLimit(state, limit); + } else { + uint32_t val = GPBCodedInputStreamReadFixed32(state); + [array addValue:val]; + } + } else if (fieldType == GPBFieldTypeSingle) { + uint32_t val = GPBCodedInputStreamReadFixed32(state); + GPBSetUInt32IvarWithFieldInternal(context->result, field, val, + context->syntax); + } else { // fieldType == GPBFieldTypeMap + // The exact type doesn't matter, just need to know it is a GPB*Dictionary. + GPBInt32Int32Dictionary *map = + GetOrCreateMapIvarWithField(context->result, field, context->syntax); + [context->stream readMapEntry:map + extensionRegistry:nil + field:field + parentMessage:context->result]; + } + return NO; +} + +//%PDDM-EXPAND MERGE_FROM_CODED_INPUT_STREAM_POD_FUNC(Int64, int64_t, Int64) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicMergeFromCodedInputStreamInt64(GPBFieldDescriptor *field, + void *voidContext) { + MergeFromCodedInputStreamContext *context = + (MergeFromCodedInputStreamContext *)voidContext; + GPBCodedInputStreamState *state = &context->stream->state_; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBInt64Array *array = + GetOrCreateArrayIvarWithField(context->result, field, context->syntax); + if (field.isPackable) { + int32_t length = GPBCodedInputStreamReadInt32(state); + size_t limit = GPBCodedInputStreamPushLimit(state, length); + while (GPBCodedInputStreamBytesUntilLimit(state) > 0) { + int64_t val = GPBCodedInputStreamReadInt64(state); + [array addValue:val]; + } + GPBCodedInputStreamPopLimit(state, limit); + } else { + int64_t val = GPBCodedInputStreamReadInt64(state); + [array addValue:val]; + } + } else if (fieldType == GPBFieldTypeSingle) { + int64_t val = GPBCodedInputStreamReadInt64(state); + GPBSetInt64IvarWithFieldInternal(context->result, field, val, + context->syntax); + } else { // fieldType == GPBFieldTypeMap + // The exact type doesn't matter, just need to know it is a GPB*Dictionary. + GPBInt32Int32Dictionary *map = + GetOrCreateMapIvarWithField(context->result, field, context->syntax); + [context->stream readMapEntry:map + extensionRegistry:nil + field:field + parentMessage:context->result]; + } + return NO; +} + +//%PDDM-EXPAND MERGE_FROM_CODED_INPUT_STREAM_POD_FUNC(SFixed64, int64_t, Int64) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicMergeFromCodedInputStreamSFixed64(GPBFieldDescriptor *field, + void *voidContext) { + MergeFromCodedInputStreamContext *context = + (MergeFromCodedInputStreamContext *)voidContext; + GPBCodedInputStreamState *state = &context->stream->state_; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBInt64Array *array = + GetOrCreateArrayIvarWithField(context->result, field, context->syntax); + if (field.isPackable) { + int32_t length = GPBCodedInputStreamReadInt32(state); + size_t limit = GPBCodedInputStreamPushLimit(state, length); + while (GPBCodedInputStreamBytesUntilLimit(state) > 0) { + int64_t val = GPBCodedInputStreamReadSFixed64(state); + [array addValue:val]; + } + GPBCodedInputStreamPopLimit(state, limit); + } else { + int64_t val = GPBCodedInputStreamReadSFixed64(state); + [array addValue:val]; + } + } else if (fieldType == GPBFieldTypeSingle) { + int64_t val = GPBCodedInputStreamReadSFixed64(state); + GPBSetInt64IvarWithFieldInternal(context->result, field, val, + context->syntax); + } else { // fieldType == GPBFieldTypeMap + // The exact type doesn't matter, just need to know it is a GPB*Dictionary. + GPBInt32Int32Dictionary *map = + GetOrCreateMapIvarWithField(context->result, field, context->syntax); + [context->stream readMapEntry:map + extensionRegistry:nil + field:field + parentMessage:context->result]; + } + return NO; +} + +//%PDDM-EXPAND MERGE_FROM_CODED_INPUT_STREAM_POD_FUNC(SInt64, int64_t, Int64) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicMergeFromCodedInputStreamSInt64(GPBFieldDescriptor *field, + void *voidContext) { + MergeFromCodedInputStreamContext *context = + (MergeFromCodedInputStreamContext *)voidContext; + GPBCodedInputStreamState *state = &context->stream->state_; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBInt64Array *array = + GetOrCreateArrayIvarWithField(context->result, field, context->syntax); + if (field.isPackable) { + int32_t length = GPBCodedInputStreamReadInt32(state); + size_t limit = GPBCodedInputStreamPushLimit(state, length); + while (GPBCodedInputStreamBytesUntilLimit(state) > 0) { + int64_t val = GPBCodedInputStreamReadSInt64(state); + [array addValue:val]; + } + GPBCodedInputStreamPopLimit(state, limit); + } else { + int64_t val = GPBCodedInputStreamReadSInt64(state); + [array addValue:val]; + } + } else if (fieldType == GPBFieldTypeSingle) { + int64_t val = GPBCodedInputStreamReadSInt64(state); + GPBSetInt64IvarWithFieldInternal(context->result, field, val, + context->syntax); + } else { // fieldType == GPBFieldTypeMap + // The exact type doesn't matter, just need to know it is a GPB*Dictionary. + GPBInt32Int32Dictionary *map = + GetOrCreateMapIvarWithField(context->result, field, context->syntax); + [context->stream readMapEntry:map + extensionRegistry:nil + field:field + parentMessage:context->result]; + } + return NO; +} + +//%PDDM-EXPAND MERGE_FROM_CODED_INPUT_STREAM_POD_FUNC(UInt64, uint64_t, UInt64) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicMergeFromCodedInputStreamUInt64(GPBFieldDescriptor *field, + void *voidContext) { + MergeFromCodedInputStreamContext *context = + (MergeFromCodedInputStreamContext *)voidContext; + GPBCodedInputStreamState *state = &context->stream->state_; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBUInt64Array *array = + GetOrCreateArrayIvarWithField(context->result, field, context->syntax); + if (field.isPackable) { + int32_t length = GPBCodedInputStreamReadInt32(state); + size_t limit = GPBCodedInputStreamPushLimit(state, length); + while (GPBCodedInputStreamBytesUntilLimit(state) > 0) { + uint64_t val = GPBCodedInputStreamReadUInt64(state); + [array addValue:val]; + } + GPBCodedInputStreamPopLimit(state, limit); + } else { + uint64_t val = GPBCodedInputStreamReadUInt64(state); + [array addValue:val]; + } + } else if (fieldType == GPBFieldTypeSingle) { + uint64_t val = GPBCodedInputStreamReadUInt64(state); + GPBSetUInt64IvarWithFieldInternal(context->result, field, val, + context->syntax); + } else { // fieldType == GPBFieldTypeMap + // The exact type doesn't matter, just need to know it is a GPB*Dictionary. + GPBInt32Int32Dictionary *map = + GetOrCreateMapIvarWithField(context->result, field, context->syntax); + [context->stream readMapEntry:map + extensionRegistry:nil + field:field + parentMessage:context->result]; + } + return NO; +} + +//%PDDM-EXPAND MERGE_FROM_CODED_INPUT_STREAM_POD_FUNC(Fixed64, uint64_t, UInt64) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicMergeFromCodedInputStreamFixed64(GPBFieldDescriptor *field, + void *voidContext) { + MergeFromCodedInputStreamContext *context = + (MergeFromCodedInputStreamContext *)voidContext; + GPBCodedInputStreamState *state = &context->stream->state_; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBUInt64Array *array = + GetOrCreateArrayIvarWithField(context->result, field, context->syntax); + if (field.isPackable) { + int32_t length = GPBCodedInputStreamReadInt32(state); + size_t limit = GPBCodedInputStreamPushLimit(state, length); + while (GPBCodedInputStreamBytesUntilLimit(state) > 0) { + uint64_t val = GPBCodedInputStreamReadFixed64(state); + [array addValue:val]; + } + GPBCodedInputStreamPopLimit(state, limit); + } else { + uint64_t val = GPBCodedInputStreamReadFixed64(state); + [array addValue:val]; + } + } else if (fieldType == GPBFieldTypeSingle) { + uint64_t val = GPBCodedInputStreamReadFixed64(state); + GPBSetUInt64IvarWithFieldInternal(context->result, field, val, + context->syntax); + } else { // fieldType == GPBFieldTypeMap + // The exact type doesn't matter, just need to know it is a GPB*Dictionary. + GPBInt32Int32Dictionary *map = + GetOrCreateMapIvarWithField(context->result, field, context->syntax); + [context->stream readMapEntry:map + extensionRegistry:nil + field:field + parentMessage:context->result]; + } + return NO; +} + +//%PDDM-EXPAND MERGE_FROM_CODED_INPUT_STREAM_POD_FUNC(Float, float, Float) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicMergeFromCodedInputStreamFloat(GPBFieldDescriptor *field, + void *voidContext) { + MergeFromCodedInputStreamContext *context = + (MergeFromCodedInputStreamContext *)voidContext; + GPBCodedInputStreamState *state = &context->stream->state_; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBFloatArray *array = + GetOrCreateArrayIvarWithField(context->result, field, context->syntax); + if (field.isPackable) { + int32_t length = GPBCodedInputStreamReadInt32(state); + size_t limit = GPBCodedInputStreamPushLimit(state, length); + while (GPBCodedInputStreamBytesUntilLimit(state) > 0) { + float val = GPBCodedInputStreamReadFloat(state); + [array addValue:val]; + } + GPBCodedInputStreamPopLimit(state, limit); + } else { + float val = GPBCodedInputStreamReadFloat(state); + [array addValue:val]; + } + } else if (fieldType == GPBFieldTypeSingle) { + float val = GPBCodedInputStreamReadFloat(state); + GPBSetFloatIvarWithFieldInternal(context->result, field, val, + context->syntax); + } else { // fieldType == GPBFieldTypeMap + // The exact type doesn't matter, just need to know it is a GPB*Dictionary. + GPBInt32Int32Dictionary *map = + GetOrCreateMapIvarWithField(context->result, field, context->syntax); + [context->stream readMapEntry:map + extensionRegistry:nil + field:field + parentMessage:context->result]; + } + return NO; +} + +//%PDDM-EXPAND MERGE_FROM_CODED_INPUT_STREAM_POD_FUNC(Double, double, Double) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicMergeFromCodedInputStreamDouble(GPBFieldDescriptor *field, + void *voidContext) { + MergeFromCodedInputStreamContext *context = + (MergeFromCodedInputStreamContext *)voidContext; + GPBCodedInputStreamState *state = &context->stream->state_; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBDoubleArray *array = + GetOrCreateArrayIvarWithField(context->result, field, context->syntax); + if (field.isPackable) { + int32_t length = GPBCodedInputStreamReadInt32(state); + size_t limit = GPBCodedInputStreamPushLimit(state, length); + while (GPBCodedInputStreamBytesUntilLimit(state) > 0) { + double val = GPBCodedInputStreamReadDouble(state); + [array addValue:val]; + } + GPBCodedInputStreamPopLimit(state, limit); + } else { + double val = GPBCodedInputStreamReadDouble(state); + [array addValue:val]; + } + } else if (fieldType == GPBFieldTypeSingle) { + double val = GPBCodedInputStreamReadDouble(state); + GPBSetDoubleIvarWithFieldInternal(context->result, field, val, + context->syntax); + } else { // fieldType == GPBFieldTypeMap + // The exact type doesn't matter, just need to know it is a GPB*Dictionary. + GPBInt32Int32Dictionary *map = + GetOrCreateMapIvarWithField(context->result, field, context->syntax); + [context->stream readMapEntry:map + extensionRegistry:nil + field:field + parentMessage:context->result]; + } + return NO; +} + +//%PDDM-EXPAND MERGE_FROM_CODED_INPUT_STREAM_OBJ_FUNC(String) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicMergeFromCodedInputStreamString(GPBFieldDescriptor *field, + void *voidContext) { + MergeFromCodedInputStreamContext *context = voidContext; + GPBCodedInputStreamState *state = &context->stream->state_; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeMap) { + // GPB*Dictionary or NSDictionary, exact type doesn't matter at this point. + id map = + GetOrCreateMapIvarWithField(context->result, field, context->syntax); + [context->stream readMapEntry:map + extensionRegistry:nil + field:field + parentMessage:context->result]; + } else { + id val = GPBCodedInputStreamReadRetainedString(state); + if (fieldType == GPBFieldTypeRepeated) { + NSMutableArray *array = + GetOrCreateArrayIvarWithField(context->result, field, context->syntax); + [array addObject:val]; + [val release]; + } else { // fieldType == GPBFieldTypeSingle + GPBSetRetainedObjectIvarWithFieldInternal(context->result, field, val, + context->syntax); + } + } + return NO; +} + +//%PDDM-EXPAND MERGE_FROM_CODED_INPUT_STREAM_OBJ_FUNC(Data) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicMergeFromCodedInputStreamData(GPBFieldDescriptor *field, + void *voidContext) { + MergeFromCodedInputStreamContext *context = voidContext; + GPBCodedInputStreamState *state = &context->stream->state_; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeMap) { + // GPB*Dictionary or NSDictionary, exact type doesn't matter at this point. + id map = + GetOrCreateMapIvarWithField(context->result, field, context->syntax); + [context->stream readMapEntry:map + extensionRegistry:nil + field:field + parentMessage:context->result]; + } else { + id val = GPBCodedInputStreamReadRetainedData(state); + if (fieldType == GPBFieldTypeRepeated) { + NSMutableArray *array = + GetOrCreateArrayIvarWithField(context->result, field, context->syntax); + [array addObject:val]; + [val release]; + } else { // fieldType == GPBFieldTypeSingle + GPBSetRetainedObjectIvarWithFieldInternal(context->result, field, val, + context->syntax); + } + } + return NO; +} + +//%PDDM-EXPAND-END (15 expansions) + +- (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input + extensionRegistry:(GPBExtensionRegistry *)extensionRegistry { + GPBDescriptor *descriptor = [self descriptor]; + GPBFileSyntax syntax = descriptor.file.syntax; + MergeFromCodedInputStreamContext context = { + self, input, self, extensionRegistry, 0, syntax + }; + GPBApplyStrictFunctions funcs = + GPBAPPLY_STRICT_FUNCTIONS_INIT(DynamicMergeFromCodedInputStream); + NSUInteger startingIndex = 0; + NSArray *fields = descriptor->fields_; + NSUInteger count = fields.count; + while (YES) { + BOOL merged = NO; + context.tag = GPBCodedInputStreamReadTag(&input->state_); + for (NSUInteger i = 0; i < count; ++i) { + if (startingIndex >= count) startingIndex = 0; + GPBFieldDescriptor *fieldDescriptor = fields[startingIndex]; + if (GPBFieldTag(fieldDescriptor) == context.tag) { + GPBApplyFunction function = funcs[GPBGetFieldType(fieldDescriptor)]; + function(fieldDescriptor, &context); + merged = YES; + break; + } else { + startingIndex += 1; + } + } + if (!merged) { + if (context.tag == 0) { + // zero signals EOF / limit reached + return; + } else { + if (GPBPreserveUnknownFields(syntax)) { + if (![self parseUnknownField:input + extensionRegistry:extensionRegistry + tag:context.tag]) { + // it's an endgroup tag + return; + } + } else { + if (![input skipField:context.tag]) { + return; + } + } + } + } + } +} + +#pragma mark - MergeFrom Support + +typedef struct MergeFromContext { + GPBMessage *other; + GPBMessage *result; + GPBFileSyntax syntax; +} MergeFromContext; + +//%PDDM-DEFINE GPB_MERGE_FROM_FUNC(NAME) +//%static BOOL MergeFrom##NAME(GPBFieldDescriptor *field, void *voidContext) { +//% MergeFromContext *context = (MergeFromContext *)voidContext; +//% BOOL otherHas = GPBGetHasIvarField(context->other, field); +//% if (otherHas) { +//% GPBSet##NAME##IvarWithFieldInternal( +//% context->result, field, GPBGet##NAME##IvarWithField(context->other, field), +//% context->syntax); +//% } +//% return YES; +//%} +//% +//%PDDM-EXPAND GPB_MERGE_FROM_FUNC(Bool) +// This block of code is generated, do not edit it directly. + +static BOOL MergeFromBool(GPBFieldDescriptor *field, void *voidContext) { + MergeFromContext *context = (MergeFromContext *)voidContext; + BOOL otherHas = GPBGetHasIvarField(context->other, field); + if (otherHas) { + GPBSetBoolIvarWithFieldInternal( + context->result, field, GPBGetBoolIvarWithField(context->other, field), + context->syntax); + } + return YES; +} + +//%PDDM-EXPAND GPB_MERGE_FROM_FUNC(Int32) +// This block of code is generated, do not edit it directly. + +static BOOL MergeFromInt32(GPBFieldDescriptor *field, void *voidContext) { + MergeFromContext *context = (MergeFromContext *)voidContext; + BOOL otherHas = GPBGetHasIvarField(context->other, field); + if (otherHas) { + GPBSetInt32IvarWithFieldInternal( + context->result, field, GPBGetInt32IvarWithField(context->other, field), + context->syntax); + } + return YES; +} + +//%PDDM-EXPAND GPB_MERGE_FROM_FUNC(UInt32) +// This block of code is generated, do not edit it directly. + +static BOOL MergeFromUInt32(GPBFieldDescriptor *field, void *voidContext) { + MergeFromContext *context = (MergeFromContext *)voidContext; + BOOL otherHas = GPBGetHasIvarField(context->other, field); + if (otherHas) { + GPBSetUInt32IvarWithFieldInternal( + context->result, field, GPBGetUInt32IvarWithField(context->other, field), + context->syntax); + } + return YES; +} + +//%PDDM-EXPAND GPB_MERGE_FROM_FUNC(Int64) +// This block of code is generated, do not edit it directly. + +static BOOL MergeFromInt64(GPBFieldDescriptor *field, void *voidContext) { + MergeFromContext *context = (MergeFromContext *)voidContext; + BOOL otherHas = GPBGetHasIvarField(context->other, field); + if (otherHas) { + GPBSetInt64IvarWithFieldInternal( + context->result, field, GPBGetInt64IvarWithField(context->other, field), + context->syntax); + } + return YES; +} + +//%PDDM-EXPAND GPB_MERGE_FROM_FUNC(UInt64) +// This block of code is generated, do not edit it directly. + +static BOOL MergeFromUInt64(GPBFieldDescriptor *field, void *voidContext) { + MergeFromContext *context = (MergeFromContext *)voidContext; + BOOL otherHas = GPBGetHasIvarField(context->other, field); + if (otherHas) { + GPBSetUInt64IvarWithFieldInternal( + context->result, field, GPBGetUInt64IvarWithField(context->other, field), + context->syntax); + } + return YES; +} + +//%PDDM-EXPAND GPB_MERGE_FROM_FUNC(Float) +// This block of code is generated, do not edit it directly. + +static BOOL MergeFromFloat(GPBFieldDescriptor *field, void *voidContext) { + MergeFromContext *context = (MergeFromContext *)voidContext; + BOOL otherHas = GPBGetHasIvarField(context->other, field); + if (otherHas) { + GPBSetFloatIvarWithFieldInternal( + context->result, field, GPBGetFloatIvarWithField(context->other, field), + context->syntax); + } + return YES; +} + +//%PDDM-EXPAND GPB_MERGE_FROM_FUNC(Double) +// This block of code is generated, do not edit it directly. + +static BOOL MergeFromDouble(GPBFieldDescriptor *field, void *voidContext) { + MergeFromContext *context = (MergeFromContext *)voidContext; + BOOL otherHas = GPBGetHasIvarField(context->other, field); + if (otherHas) { + GPBSetDoubleIvarWithFieldInternal( + context->result, field, GPBGetDoubleIvarWithField(context->other, field), + context->syntax); + } + return YES; +} + +//%PDDM-EXPAND-END (7 expansions) + +static BOOL MergeFromObject(GPBFieldDescriptor *field, void *voidContext) { + MergeFromContext *context = (MergeFromContext *)voidContext; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + // In the case of a list, they need to be appended, and there is no + // _hasIvar to worry about setting. + id otherArray = + GPBGetObjectIvarWithFieldNoAutocreate(context->other, field); + if (otherArray) { + GPBType fieldDataType = field->description_->type; + if (GPBTypeIsObject(fieldDataType)) { + NSMutableArray *resultArray = GetOrCreateArrayIvarWithField( + context->result, field, context->syntax); + [resultArray addObjectsFromArray:otherArray]; + } else if (fieldDataType == GPBTypeEnum) { + GPBEnumArray *resultArray = GetOrCreateArrayIvarWithField( + context->result, field, context->syntax); + [resultArray addRawValuesFromArray:otherArray]; + } else { + // The array type doesn't matter, that all implment + // -addValuesFromArray:. + GPBInt32Array *resultArray = GetOrCreateArrayIvarWithField( + context->result, field, context->syntax); + [resultArray addValuesFromArray:otherArray]; + } + } + return YES; + } + if (fieldType == GPBFieldTypeMap) { + // In the case of a map, they need to be merged, and there is no + // _hasIvar to worry about setting. + id otherDict = GPBGetObjectIvarWithFieldNoAutocreate(context->other, field); + if (otherDict) { + GPBType keyType = field.mapKeyType; + GPBType valueType = field->description_->type; + if (GPBTypeIsObject(keyType) && GPBTypeIsObject(valueType)) { + NSMutableDictionary *resultDict = GetOrCreateMapIvarWithField( + context->result, field, context->syntax); + [resultDict addEntriesFromDictionary:otherDict]; + } else if (valueType == GPBTypeEnum) { + // The exact type doesn't matter, just need to know it is a + // GPB*EnumDictionary. + GPBInt32EnumDictionary *resultDict = GetOrCreateMapIvarWithField( + context->result, field, context->syntax); + [resultDict addRawEntriesFromDictionary:otherDict]; + } else { + // The exact type doesn't matter, they all implement + // -addEntriesFromDictionary:. + GPBInt32Int32Dictionary *resultDict = GetOrCreateMapIvarWithField( + context->result, field, context->syntax); + [resultDict addEntriesFromDictionary:otherDict]; + } + } + return YES; + } + + int32_t hasIndex = GPBFieldHasIndex(field); + uint32_t fieldNumber = GPBFieldNumber(field); + BOOL otherHas = GPBGetHasIvar(context->other, hasIndex, fieldNumber); + if (!otherHas) { + return YES; + } + // GPBGetObjectIvarWithFieldNoAutocreate skips the has check, faster. + id otherVal = GPBGetObjectIvarWithFieldNoAutocreate(context->other, field); + if (GPBFieldTypeIsMessage(field)) { + if (GPBGetHasIvar(context->result, hasIndex, fieldNumber)) { + GPBMessage *message = + GPBGetObjectIvarWithFieldNoAutocreate(context->result, field); + [message mergeFrom:otherVal]; + } else { + GPBMessage *message = [otherVal copy]; + GPBSetRetainedObjectIvarWithFieldInternal(context->result, field, message, + context->syntax); + } + } else { + GPBSetObjectIvarWithFieldInternal(context->result, field, otherVal, + context->syntax); + } + return YES; +} + +- (void)mergeFrom:(GPBMessage *)other { + Class selfClass = [self class]; + Class otherClass = [other class]; + if (!([selfClass isSubclassOfClass:otherClass] || + [otherClass isSubclassOfClass:selfClass])) { + [NSException raise:NSInvalidArgumentException + format:@"Classes must match %@ != %@", selfClass, otherClass]; + } + + GPBApplyFunctions funcs = GPBAPPLY_FUNCTIONS_INIT(MergeFrom); + GPBFileSyntax syntax = [self descriptor].file.syntax; + MergeFromContext context = {other, self, syntax}; + GPBApplyFunctionsToMessageFields(&funcs, self, &context); + + // We assume someting got done, and become visible. + GPBBecomeVisibleToAutocreator(self); + + // Unknown fields. + if (!unknownFields_) { + [self setUnknownFields:context.other.unknownFields]; + } else { + [unknownFields_ mergeUnknownFields:context.other.unknownFields]; + } + + if (other->extensionMap_.count == 0) { + return; + } + + if (extensionMap_ == nil) { + extensionMap_ = + CloneExtensionMap(other->extensionMap_, NSZoneFromPointer(self)); + } else { + for (GPBExtensionField *thisField in other->extensionMap_) { + id otherValue = [other->extensionMap_ objectForKey:thisField]; + id value = [extensionMap_ objectForKey:thisField]; + GPBExtensionDescriptor *thisFieldDescriptor = thisField.descriptor; + BOOL isMessageExtension = GPBExtensionIsMessage(thisFieldDescriptor); + + if ([thisField isRepeated]) { + NSMutableArray *list = value; + if (list == nil) { + list = [[NSMutableArray alloc] init]; + [extensionMap_ setObject:list forKey:thisField]; + [list release]; + } + if (isMessageExtension) { + for (GPBMessage *otherListValue in otherValue) { + GPBMessage *copiedValue = [otherListValue copy]; + [list addObject:copiedValue]; + [copiedValue release]; + } + } else { + [list addObjectsFromArray:otherValue]; + } + } else { + if (isMessageExtension) { + if (value) { + [(GPBMessage *)value mergeFrom:(GPBMessage *)otherValue]; + } else { + GPBMessage *copiedValue = [otherValue copy]; + [extensionMap_ setObject:copiedValue forKey:thisField]; + [copiedValue release]; + } + } else { + [extensionMap_ setObject:otherValue forKey:thisField]; + } + } + + if (isMessageExtension && !thisFieldDescriptor.isRepeated) { + GPBMessage *autocreatedValue = + [[autocreatedExtensionMap_ objectForKey:thisField] retain]; + // Must remove from the map before calling GPBClearMessageAutocreator() + // so that GPBClearMessageAutocreator() knows its safe to clear. + [autocreatedExtensionMap_ removeObjectForKey:thisField]; + GPBClearMessageAutocreator(autocreatedValue); + [autocreatedValue release]; + } + } + } +} + +#pragma mark - IsEqual Support + +typedef struct IsEqualContext { + GPBMessage *other; + GPBMessage *self; + BOOL outIsEqual; +} IsEqualContext; + +// If both self and other "has" a value then compare. +//%PDDM-DEFINE IS_EQUAL_FUNC(NAME, TYPE) +//%static BOOL IsEqual##NAME(GPBFieldDescriptor *field, void *voidContext) { +//% IsEqualContext *context = (IsEqualContext *)voidContext; +//% int32_t hasIndex = GPBFieldHasIndex(field); +//% uint32_t fieldNum = GPBFieldNumber(field); +//% BOOL selfHas = GPBGetHasIvar(context->self, hasIndex, fieldNum); +//% BOOL otherHas = GPBGetHasIvar(context->other, hasIndex, fieldNum); +//% if (selfHas != otherHas) { +//% context->outIsEqual = NO; +//% return NO; +//% } +//% if (!selfHas) { +//% return YES; +//% } +//% TYPE selfVal = GPBGet##NAME##IvarWithField(context->self, field); +//% TYPE otherVal = GPBGet##NAME##IvarWithField(context->other, field); +//% if (selfVal != otherVal) { +//% context->outIsEqual = NO; +//% return NO; +//% } +//% return YES; +//%} +//% +//%PDDM-EXPAND IS_EQUAL_FUNC(Bool, BOOL) +// This block of code is generated, do not edit it directly. + +static BOOL IsEqualBool(GPBFieldDescriptor *field, void *voidContext) { + IsEqualContext *context = (IsEqualContext *)voidContext; + int32_t hasIndex = GPBFieldHasIndex(field); + uint32_t fieldNum = GPBFieldNumber(field); + BOOL selfHas = GPBGetHasIvar(context->self, hasIndex, fieldNum); + BOOL otherHas = GPBGetHasIvar(context->other, hasIndex, fieldNum); + if (selfHas != otherHas) { + context->outIsEqual = NO; + return NO; + } + if (!selfHas) { + return YES; + } + BOOL selfVal = GPBGetBoolIvarWithField(context->self, field); + BOOL otherVal = GPBGetBoolIvarWithField(context->other, field); + if (selfVal != otherVal) { + context->outIsEqual = NO; + return NO; + } + return YES; +} + +//%PDDM-EXPAND IS_EQUAL_FUNC(Int32, int32_t) +// This block of code is generated, do not edit it directly. + +static BOOL IsEqualInt32(GPBFieldDescriptor *field, void *voidContext) { + IsEqualContext *context = (IsEqualContext *)voidContext; + int32_t hasIndex = GPBFieldHasIndex(field); + uint32_t fieldNum = GPBFieldNumber(field); + BOOL selfHas = GPBGetHasIvar(context->self, hasIndex, fieldNum); + BOOL otherHas = GPBGetHasIvar(context->other, hasIndex, fieldNum); + if (selfHas != otherHas) { + context->outIsEqual = NO; + return NO; + } + if (!selfHas) { + return YES; + } + int32_t selfVal = GPBGetInt32IvarWithField(context->self, field); + int32_t otherVal = GPBGetInt32IvarWithField(context->other, field); + if (selfVal != otherVal) { + context->outIsEqual = NO; + return NO; + } + return YES; +} + +//%PDDM-EXPAND IS_EQUAL_FUNC(UInt32, uint32_t) +// This block of code is generated, do not edit it directly. + +static BOOL IsEqualUInt32(GPBFieldDescriptor *field, void *voidContext) { + IsEqualContext *context = (IsEqualContext *)voidContext; + int32_t hasIndex = GPBFieldHasIndex(field); + uint32_t fieldNum = GPBFieldNumber(field); + BOOL selfHas = GPBGetHasIvar(context->self, hasIndex, fieldNum); + BOOL otherHas = GPBGetHasIvar(context->other, hasIndex, fieldNum); + if (selfHas != otherHas) { + context->outIsEqual = NO; + return NO; + } + if (!selfHas) { + return YES; + } + uint32_t selfVal = GPBGetUInt32IvarWithField(context->self, field); + uint32_t otherVal = GPBGetUInt32IvarWithField(context->other, field); + if (selfVal != otherVal) { + context->outIsEqual = NO; + return NO; + } + return YES; +} + +//%PDDM-EXPAND IS_EQUAL_FUNC(Int64, int64_t) +// This block of code is generated, do not edit it directly. + +static BOOL IsEqualInt64(GPBFieldDescriptor *field, void *voidContext) { + IsEqualContext *context = (IsEqualContext *)voidContext; + int32_t hasIndex = GPBFieldHasIndex(field); + uint32_t fieldNum = GPBFieldNumber(field); + BOOL selfHas = GPBGetHasIvar(context->self, hasIndex, fieldNum); + BOOL otherHas = GPBGetHasIvar(context->other, hasIndex, fieldNum); + if (selfHas != otherHas) { + context->outIsEqual = NO; + return NO; + } + if (!selfHas) { + return YES; + } + int64_t selfVal = GPBGetInt64IvarWithField(context->self, field); + int64_t otherVal = GPBGetInt64IvarWithField(context->other, field); + if (selfVal != otherVal) { + context->outIsEqual = NO; + return NO; + } + return YES; +} + +//%PDDM-EXPAND IS_EQUAL_FUNC(UInt64, uint64_t) +// This block of code is generated, do not edit it directly. + +static BOOL IsEqualUInt64(GPBFieldDescriptor *field, void *voidContext) { + IsEqualContext *context = (IsEqualContext *)voidContext; + int32_t hasIndex = GPBFieldHasIndex(field); + uint32_t fieldNum = GPBFieldNumber(field); + BOOL selfHas = GPBGetHasIvar(context->self, hasIndex, fieldNum); + BOOL otherHas = GPBGetHasIvar(context->other, hasIndex, fieldNum); + if (selfHas != otherHas) { + context->outIsEqual = NO; + return NO; + } + if (!selfHas) { + return YES; + } + uint64_t selfVal = GPBGetUInt64IvarWithField(context->self, field); + uint64_t otherVal = GPBGetUInt64IvarWithField(context->other, field); + if (selfVal != otherVal) { + context->outIsEqual = NO; + return NO; + } + return YES; +} + +//%PDDM-EXPAND IS_EQUAL_FUNC(Float, float) +// This block of code is generated, do not edit it directly. + +static BOOL IsEqualFloat(GPBFieldDescriptor *field, void *voidContext) { + IsEqualContext *context = (IsEqualContext *)voidContext; + int32_t hasIndex = GPBFieldHasIndex(field); + uint32_t fieldNum = GPBFieldNumber(field); + BOOL selfHas = GPBGetHasIvar(context->self, hasIndex, fieldNum); + BOOL otherHas = GPBGetHasIvar(context->other, hasIndex, fieldNum); + if (selfHas != otherHas) { + context->outIsEqual = NO; + return NO; + } + if (!selfHas) { + return YES; + } + float selfVal = GPBGetFloatIvarWithField(context->self, field); + float otherVal = GPBGetFloatIvarWithField(context->other, field); + if (selfVal != otherVal) { + context->outIsEqual = NO; + return NO; + } + return YES; +} + +//%PDDM-EXPAND IS_EQUAL_FUNC(Double, double) +// This block of code is generated, do not edit it directly. + +static BOOL IsEqualDouble(GPBFieldDescriptor *field, void *voidContext) { + IsEqualContext *context = (IsEqualContext *)voidContext; + int32_t hasIndex = GPBFieldHasIndex(field); + uint32_t fieldNum = GPBFieldNumber(field); + BOOL selfHas = GPBGetHasIvar(context->self, hasIndex, fieldNum); + BOOL otherHas = GPBGetHasIvar(context->other, hasIndex, fieldNum); + if (selfHas != otherHas) { + context->outIsEqual = NO; + return NO; + } + if (!selfHas) { + return YES; + } + double selfVal = GPBGetDoubleIvarWithField(context->self, field); + double otherVal = GPBGetDoubleIvarWithField(context->other, field); + if (selfVal != otherVal) { + context->outIsEqual = NO; + return NO; + } + return YES; +} + +//%PDDM-EXPAND-END (7 expansions) + +static BOOL IsEqualObject(GPBFieldDescriptor *field, void *voidContext) { + IsEqualContext *context = (IsEqualContext *)voidContext; + if (GPBFieldIsMapOrArray(field)) { + // In the case of a list/map, there is no _hasIvar to worry about checking. + // NOTE: These are NSArray/GPB*Array/NSDictionary/GPB*Dictionary, but the + // type doesn't really matter as the object just has to support + // -count/-isEqual:. + NSArray *resultMapOrArray = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + NSArray *otherMapOrArray = + GPBGetObjectIvarWithFieldNoAutocreate(context->other, field); + context->outIsEqual = + (resultMapOrArray.count == 0 && otherMapOrArray.count == 0) || + [resultMapOrArray isEqual:otherMapOrArray]; + return context->outIsEqual; + } + int32_t hasIndex = GPBFieldHasIndex(field); + uint32_t fieldNum = GPBFieldNumber(field); + BOOL selfHas = GPBGetHasIvar(context->self, hasIndex, fieldNum); + BOOL otherHas = GPBGetHasIvar(context->other, hasIndex, fieldNum); + if (selfHas != otherHas) { + context->outIsEqual = NO; + return NO; + } + if (!selfHas) { + return YES; + } + // GPBGetObjectIvarWithFieldNoAutocreate skips the has check, faster. + NSObject *selfVal = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + NSObject *otherVal = + GPBGetObjectIvarWithFieldNoAutocreate(context->other, field); + + // This covers case where selfVal is set to nil, as well as shortcuts the call + // to isEqual: in common cases. + if (selfVal == otherVal) { + return YES; + } + if (![selfVal isEqual:otherVal]) { + context->outIsEqual = NO; + return NO; + } + return YES; +} + +- (BOOL)isEqual:(GPBMessage *)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[self class]] && + ![self isKindOfClass:[other class]]) { + return NO; + } + GPBApplyFunctions funcs = GPBAPPLY_FUNCTIONS_INIT(IsEqual); + IsEqualContext context = {other, self, YES}; + GPBApplyFunctionsToMessageFields(&funcs, self, &context); + if (!context.outIsEqual) { + return NO; + } + + // nil and empty are equal + if (extensionMap_.count != 0 || other->extensionMap_.count != 0) { + if (![extensionMap_ isEqual:other->extensionMap_]) { + return NO; + } + } + + // nil and empty are equal + GPBUnknownFieldSet *otherUnknowns = other.unknownFields; + if ([unknownFields_ countOfFields] != 0 || + [otherUnknowns countOfFields] != 0) { + if (![unknownFields_ isEqual:otherUnknowns]) { + return NO; + } + } + return YES; +} + +// It is very difficult to implement a generic hash for ProtoBuf messages that +// will perform well. If you need hashing on your ProtoBufs (eg you are using +// them as dictionary keys) you will probably want to implement a ProtoBuf +// message specific hash as a category on your protobuf class. Do not make it a +// category on GPBMessage as you will conflict with this hash, and will possibly +// override hash for all generated protobufs. A good implementation of hash will +// be really fast, so we would recommend only hashing protobufs that have an +// identifier field of some kind that you can easily hash. If you implement +// hash, we would strongly recommend overriding isEqual: in your category as +// well, as the default implementation of isEqual: is extremely slow, and may +// drastically affect performance in large sets. +- (NSUInteger)hash { + GPBDescriptor *descriptor = [[self class] descriptor]; + const NSUInteger prime = 19; + + // Start with the descriptor and then mix it with the field numbers that + // are set. Hopefully that will give a spread based on classes and what + // fields are set. + NSUInteger result = (NSUInteger)descriptor; + for (GPBFieldDescriptor *field in descriptor->fields_) { + if (GPBFieldIsMapOrArray(field)) { + // Exact type doesn't matter, just check if there are any elements. + NSArray *mapOrArray = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + if (mapOrArray.count) { + result = prime * result + GPBFieldNumber(field); + } + } else if (GPBGetHasIvarField(self, field)) { + result = prime * result + GPBFieldNumber(field); + } + } + return result; +} + +#pragma mark - Description Support + +- (NSString *)description { + NSString *textFormat = GPBTextFormatForMessage(self, @" "); + NSString *description = [NSString + stringWithFormat:@"<%@ %p>: {\n%@}", [self class], self, textFormat]; + return description; +} + +#if DEBUG + +// Xcode 5.1 added support for custom quick look info. +// https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/CustomClassDisplay_in_QuickLook/CH01-quick_look_for_custom_objects/CH01-quick_look_for_custom_objects.html#//apple_ref/doc/uid/TP40014001-CH2-SW1 +- (id)debugQuickLookObject { + return GPBTextFormatForMessage(self, nil); +} + +#endif // DEBUG + +#pragma mark - SerializedSize Support + +// Serialized size is only calculated once, and then is stored into +// memoizedSerializedSize. + +typedef struct SerializedSizeContext { + GPBMessage *self; + size_t outSize; +} SerializedSizeContext; + +//%PDDM-DEFINE SERIALIZED_SIZE_POD_FUNC(NAME, TYPE, REAL_TYPE) +//%SERIALIZED_SIZE_POD_FUNC_FULL(NAME, TYPE, REAL_TYPE, REAL_TYPE, ) +//%PDDM-DEFINE SERIALIZED_SIZE_POD_FUNC_FULL(NAME, TYPE, REAL_TYPE, ARRAY_TYPE, ARRAY_ACCESSOR_NAME) +//%static BOOL DynamicSerializedSize##NAME(GPBFieldDescriptor *field, +//% NAME$S void *voidContext) { +//% SerializedSizeContext *context = (SerializedSizeContext *)voidContext; +//% GPBFieldType fieldType = field.fieldType; +//% if (fieldType == GPBFieldTypeRepeated) { +//% GPB##ARRAY_TYPE##Array *array = +//% GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); +//% NSUInteger count = array.count; +//% if (count == 0) return YES; +//% __block size_t dataSize = 0; +//% [array enumerate##ARRAY_ACCESSOR_NAME##ValuesWithBlock:^(TYPE value, NSUInteger idx, BOOL *stop) { +//% #pragma unused(idx, stop) +//% dataSize += GPBCompute##NAME##SizeNoTag(value); +//% }]; +//% context->outSize += dataSize; +//% size_t tagSize = GPBComputeTagSize(GPBFieldNumber(field)); +//% if (field.isPackable) { +//% context->outSize += tagSize; +//% context->outSize += GPBComputeSizeTSizeAsInt32NoTag(dataSize); +//% } else { +//% context->outSize += count * tagSize; +//% } +//% } else if (fieldType == GPBFieldTypeSingle) { +//% BOOL selfHas = GPBGetHasIvarField(context->self, field); +//% if (selfHas) { +//% TYPE selfVal = GPBGet##REAL_TYPE##IvarWithField(context->self, field); +//% context->outSize += GPBCompute##NAME##Size(GPBFieldNumber(field), selfVal); +//% } +//% } else { // fieldType == GPBFieldTypeMap +//% // Type will be GPB*##REAL_TYPE##Dictionary, exact type doesn't matter. +//% GPBInt32##REAL_TYPE##Dictionary *map = +//% GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); +//% context->outSize += [map computeSerializedSizeAsField:field]; +//% } +//% return YES; +//%} +//% +//%PDDM-DEFINE SERIALIZED_SIZE_OBJECT_FUNC(NAME) +//%static BOOL DynamicSerializedSize##NAME(GPBFieldDescriptor *field, +//% NAME$S void *voidContext) { +//% SerializedSizeContext *context = (SerializedSizeContext *)voidContext; +//% GPBFieldType fieldType = field.fieldType; +//% if (fieldType == GPBFieldTypeRepeated) { +//% NSArray *array = +//% GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); +//% for (id value in array) { +//% context->outSize += GPBCompute##NAME##SizeNoTag(value); +//% } +//% size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), +//% GPBGetFieldType(field)); +//% context->outSize += array.count * tagSize; +//% } else if (fieldType == GPBFieldTypeSingle) { +//% BOOL selfHas = GPBGetHasIvarField(context->self, field); +//% if (selfHas) { +//% // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check +//% // again. +//% id selfVal = GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); +//% context->outSize += GPBCompute##NAME##Size(GPBFieldNumber(field), selfVal); +//% } +//% } else { // fieldType == GPBFieldTypeMap +//% GPBType mapKeyType = field.mapKeyType; +//% if (mapKeyType == GPBTypeString) { +//% // If key type was string, then the map is an NSDictionary. +//% NSDictionary *map = +//% GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); +//% context->outSize += GPBDictionaryComputeSizeInternalHelper(map, field); +//% } else { +//% // Type will be GPB*##NAME##Dictionary, exact type doesn't matter. +//% GPBInt32ObjectDictionary *map = +//% GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); +//% context->outSize += [map computeSerializedSizeAsField:field]; +//% } +//% } +//% return YES; +//%} +//% +//%PDDM-EXPAND SERIALIZED_SIZE_POD_FUNC(Bool, BOOL, Bool) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicSerializedSizeBool(GPBFieldDescriptor *field, + void *voidContext) { + SerializedSizeContext *context = (SerializedSizeContext *)voidContext; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBBoolArray *array = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + NSUInteger count = array.count; + if (count == 0) return YES; + __block size_t dataSize = 0; + [array enumerateValuesWithBlock:^(BOOL value, NSUInteger idx, BOOL *stop) { + #pragma unused(idx, stop) + dataSize += GPBComputeBoolSizeNoTag(value); + }]; + context->outSize += dataSize; + size_t tagSize = GPBComputeTagSize(GPBFieldNumber(field)); + if (field.isPackable) { + context->outSize += tagSize; + context->outSize += GPBComputeSizeTSizeAsInt32NoTag(dataSize); + } else { + context->outSize += count * tagSize; + } + } else if (fieldType == GPBFieldTypeSingle) { + BOOL selfHas = GPBGetHasIvarField(context->self, field); + if (selfHas) { + BOOL selfVal = GPBGetBoolIvarWithField(context->self, field); + context->outSize += GPBComputeBoolSize(GPBFieldNumber(field), selfVal); + } + } else { // fieldType == GPBFieldTypeMap + // Type will be GPB*BoolDictionary, exact type doesn't matter. + GPBInt32BoolDictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += [map computeSerializedSizeAsField:field]; + } + return YES; +} + +//%PDDM-EXPAND SERIALIZED_SIZE_POD_FUNC(Int32, int32_t, Int32) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicSerializedSizeInt32(GPBFieldDescriptor *field, + void *voidContext) { + SerializedSizeContext *context = (SerializedSizeContext *)voidContext; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBInt32Array *array = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + NSUInteger count = array.count; + if (count == 0) return YES; + __block size_t dataSize = 0; + [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(idx, stop) + dataSize += GPBComputeInt32SizeNoTag(value); + }]; + context->outSize += dataSize; + size_t tagSize = GPBComputeTagSize(GPBFieldNumber(field)); + if (field.isPackable) { + context->outSize += tagSize; + context->outSize += GPBComputeSizeTSizeAsInt32NoTag(dataSize); + } else { + context->outSize += count * tagSize; + } + } else if (fieldType == GPBFieldTypeSingle) { + BOOL selfHas = GPBGetHasIvarField(context->self, field); + if (selfHas) { + int32_t selfVal = GPBGetInt32IvarWithField(context->self, field); + context->outSize += GPBComputeInt32Size(GPBFieldNumber(field), selfVal); + } + } else { // fieldType == GPBFieldTypeMap + // Type will be GPB*Int32Dictionary, exact type doesn't matter. + GPBInt32Int32Dictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += [map computeSerializedSizeAsField:field]; + } + return YES; +} + +//%PDDM-EXPAND SERIALIZED_SIZE_POD_FUNC(SInt32, int32_t, Int32) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicSerializedSizeSInt32(GPBFieldDescriptor *field, + void *voidContext) { + SerializedSizeContext *context = (SerializedSizeContext *)voidContext; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBInt32Array *array = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + NSUInteger count = array.count; + if (count == 0) return YES; + __block size_t dataSize = 0; + [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(idx, stop) + dataSize += GPBComputeSInt32SizeNoTag(value); + }]; + context->outSize += dataSize; + size_t tagSize = GPBComputeTagSize(GPBFieldNumber(field)); + if (field.isPackable) { + context->outSize += tagSize; + context->outSize += GPBComputeSizeTSizeAsInt32NoTag(dataSize); + } else { + context->outSize += count * tagSize; + } + } else if (fieldType == GPBFieldTypeSingle) { + BOOL selfHas = GPBGetHasIvarField(context->self, field); + if (selfHas) { + int32_t selfVal = GPBGetInt32IvarWithField(context->self, field); + context->outSize += GPBComputeSInt32Size(GPBFieldNumber(field), selfVal); + } + } else { // fieldType == GPBFieldTypeMap + // Type will be GPB*Int32Dictionary, exact type doesn't matter. + GPBInt32Int32Dictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += [map computeSerializedSizeAsField:field]; + } + return YES; +} + +//%PDDM-EXPAND SERIALIZED_SIZE_POD_FUNC(SFixed32, int32_t, Int32) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicSerializedSizeSFixed32(GPBFieldDescriptor *field, + void *voidContext) { + SerializedSizeContext *context = (SerializedSizeContext *)voidContext; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBInt32Array *array = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + NSUInteger count = array.count; + if (count == 0) return YES; + __block size_t dataSize = 0; + [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(idx, stop) + dataSize += GPBComputeSFixed32SizeNoTag(value); + }]; + context->outSize += dataSize; + size_t tagSize = GPBComputeTagSize(GPBFieldNumber(field)); + if (field.isPackable) { + context->outSize += tagSize; + context->outSize += GPBComputeSizeTSizeAsInt32NoTag(dataSize); + } else { + context->outSize += count * tagSize; + } + } else if (fieldType == GPBFieldTypeSingle) { + BOOL selfHas = GPBGetHasIvarField(context->self, field); + if (selfHas) { + int32_t selfVal = GPBGetInt32IvarWithField(context->self, field); + context->outSize += GPBComputeSFixed32Size(GPBFieldNumber(field), selfVal); + } + } else { // fieldType == GPBFieldTypeMap + // Type will be GPB*Int32Dictionary, exact type doesn't matter. + GPBInt32Int32Dictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += [map computeSerializedSizeAsField:field]; + } + return YES; +} + +//%PDDM-EXPAND SERIALIZED_SIZE_POD_FUNC_FULL(Enum, int32_t, Int32, Enum, Raw) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicSerializedSizeEnum(GPBFieldDescriptor *field, + void *voidContext) { + SerializedSizeContext *context = (SerializedSizeContext *)voidContext; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBEnumArray *array = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + NSUInteger count = array.count; + if (count == 0) return YES; + __block size_t dataSize = 0; + [array enumerateRawValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(idx, stop) + dataSize += GPBComputeEnumSizeNoTag(value); + }]; + context->outSize += dataSize; + size_t tagSize = GPBComputeTagSize(GPBFieldNumber(field)); + if (field.isPackable) { + context->outSize += tagSize; + context->outSize += GPBComputeSizeTSizeAsInt32NoTag(dataSize); + } else { + context->outSize += count * tagSize; + } + } else if (fieldType == GPBFieldTypeSingle) { + BOOL selfHas = GPBGetHasIvarField(context->self, field); + if (selfHas) { + int32_t selfVal = GPBGetInt32IvarWithField(context->self, field); + context->outSize += GPBComputeEnumSize(GPBFieldNumber(field), selfVal); + } + } else { // fieldType == GPBFieldTypeMap + // Type will be GPB*Int32Dictionary, exact type doesn't matter. + GPBInt32Int32Dictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += [map computeSerializedSizeAsField:field]; + } + return YES; +} + +//%PDDM-EXPAND SERIALIZED_SIZE_POD_FUNC(UInt32, uint32_t, UInt32) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicSerializedSizeUInt32(GPBFieldDescriptor *field, + void *voidContext) { + SerializedSizeContext *context = (SerializedSizeContext *)voidContext; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBUInt32Array *array = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + NSUInteger count = array.count; + if (count == 0) return YES; + __block size_t dataSize = 0; + [array enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(idx, stop) + dataSize += GPBComputeUInt32SizeNoTag(value); + }]; + context->outSize += dataSize; + size_t tagSize = GPBComputeTagSize(GPBFieldNumber(field)); + if (field.isPackable) { + context->outSize += tagSize; + context->outSize += GPBComputeSizeTSizeAsInt32NoTag(dataSize); + } else { + context->outSize += count * tagSize; + } + } else if (fieldType == GPBFieldTypeSingle) { + BOOL selfHas = GPBGetHasIvarField(context->self, field); + if (selfHas) { + uint32_t selfVal = GPBGetUInt32IvarWithField(context->self, field); + context->outSize += GPBComputeUInt32Size(GPBFieldNumber(field), selfVal); + } + } else { // fieldType == GPBFieldTypeMap + // Type will be GPB*UInt32Dictionary, exact type doesn't matter. + GPBInt32UInt32Dictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += [map computeSerializedSizeAsField:field]; + } + return YES; +} + +//%PDDM-EXPAND SERIALIZED_SIZE_POD_FUNC(Fixed32, uint32_t, UInt32) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicSerializedSizeFixed32(GPBFieldDescriptor *field, + void *voidContext) { + SerializedSizeContext *context = (SerializedSizeContext *)voidContext; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBUInt32Array *array = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + NSUInteger count = array.count; + if (count == 0) return YES; + __block size_t dataSize = 0; + [array enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(idx, stop) + dataSize += GPBComputeFixed32SizeNoTag(value); + }]; + context->outSize += dataSize; + size_t tagSize = GPBComputeTagSize(GPBFieldNumber(field)); + if (field.isPackable) { + context->outSize += tagSize; + context->outSize += GPBComputeSizeTSizeAsInt32NoTag(dataSize); + } else { + context->outSize += count * tagSize; + } + } else if (fieldType == GPBFieldTypeSingle) { + BOOL selfHas = GPBGetHasIvarField(context->self, field); + if (selfHas) { + uint32_t selfVal = GPBGetUInt32IvarWithField(context->self, field); + context->outSize += GPBComputeFixed32Size(GPBFieldNumber(field), selfVal); + } + } else { // fieldType == GPBFieldTypeMap + // Type will be GPB*UInt32Dictionary, exact type doesn't matter. + GPBInt32UInt32Dictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += [map computeSerializedSizeAsField:field]; + } + return YES; +} + +//%PDDM-EXPAND SERIALIZED_SIZE_POD_FUNC(Int64, int64_t, Int64) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicSerializedSizeInt64(GPBFieldDescriptor *field, + void *voidContext) { + SerializedSizeContext *context = (SerializedSizeContext *)voidContext; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBInt64Array *array = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + NSUInteger count = array.count; + if (count == 0) return YES; + __block size_t dataSize = 0; + [array enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(idx, stop) + dataSize += GPBComputeInt64SizeNoTag(value); + }]; + context->outSize += dataSize; + size_t tagSize = GPBComputeTagSize(GPBFieldNumber(field)); + if (field.isPackable) { + context->outSize += tagSize; + context->outSize += GPBComputeSizeTSizeAsInt32NoTag(dataSize); + } else { + context->outSize += count * tagSize; + } + } else if (fieldType == GPBFieldTypeSingle) { + BOOL selfHas = GPBGetHasIvarField(context->self, field); + if (selfHas) { + int64_t selfVal = GPBGetInt64IvarWithField(context->self, field); + context->outSize += GPBComputeInt64Size(GPBFieldNumber(field), selfVal); + } + } else { // fieldType == GPBFieldTypeMap + // Type will be GPB*Int64Dictionary, exact type doesn't matter. + GPBInt32Int64Dictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += [map computeSerializedSizeAsField:field]; + } + return YES; +} + +//%PDDM-EXPAND SERIALIZED_SIZE_POD_FUNC(SFixed64, int64_t, Int64) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicSerializedSizeSFixed64(GPBFieldDescriptor *field, + void *voidContext) { + SerializedSizeContext *context = (SerializedSizeContext *)voidContext; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBInt64Array *array = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + NSUInteger count = array.count; + if (count == 0) return YES; + __block size_t dataSize = 0; + [array enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(idx, stop) + dataSize += GPBComputeSFixed64SizeNoTag(value); + }]; + context->outSize += dataSize; + size_t tagSize = GPBComputeTagSize(GPBFieldNumber(field)); + if (field.isPackable) { + context->outSize += tagSize; + context->outSize += GPBComputeSizeTSizeAsInt32NoTag(dataSize); + } else { + context->outSize += count * tagSize; + } + } else if (fieldType == GPBFieldTypeSingle) { + BOOL selfHas = GPBGetHasIvarField(context->self, field); + if (selfHas) { + int64_t selfVal = GPBGetInt64IvarWithField(context->self, field); + context->outSize += GPBComputeSFixed64Size(GPBFieldNumber(field), selfVal); + } + } else { // fieldType == GPBFieldTypeMap + // Type will be GPB*Int64Dictionary, exact type doesn't matter. + GPBInt32Int64Dictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += [map computeSerializedSizeAsField:field]; + } + return YES; +} + +//%PDDM-EXPAND SERIALIZED_SIZE_POD_FUNC(SInt64, int64_t, Int64) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicSerializedSizeSInt64(GPBFieldDescriptor *field, + void *voidContext) { + SerializedSizeContext *context = (SerializedSizeContext *)voidContext; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBInt64Array *array = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + NSUInteger count = array.count; + if (count == 0) return YES; + __block size_t dataSize = 0; + [array enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(idx, stop) + dataSize += GPBComputeSInt64SizeNoTag(value); + }]; + context->outSize += dataSize; + size_t tagSize = GPBComputeTagSize(GPBFieldNumber(field)); + if (field.isPackable) { + context->outSize += tagSize; + context->outSize += GPBComputeSizeTSizeAsInt32NoTag(dataSize); + } else { + context->outSize += count * tagSize; + } + } else if (fieldType == GPBFieldTypeSingle) { + BOOL selfHas = GPBGetHasIvarField(context->self, field); + if (selfHas) { + int64_t selfVal = GPBGetInt64IvarWithField(context->self, field); + context->outSize += GPBComputeSInt64Size(GPBFieldNumber(field), selfVal); + } + } else { // fieldType == GPBFieldTypeMap + // Type will be GPB*Int64Dictionary, exact type doesn't matter. + GPBInt32Int64Dictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += [map computeSerializedSizeAsField:field]; + } + return YES; +} + +//%PDDM-EXPAND SERIALIZED_SIZE_POD_FUNC(UInt64, uint64_t, UInt64) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicSerializedSizeUInt64(GPBFieldDescriptor *field, + void *voidContext) { + SerializedSizeContext *context = (SerializedSizeContext *)voidContext; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBUInt64Array *array = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + NSUInteger count = array.count; + if (count == 0) return YES; + __block size_t dataSize = 0; + [array enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(idx, stop) + dataSize += GPBComputeUInt64SizeNoTag(value); + }]; + context->outSize += dataSize; + size_t tagSize = GPBComputeTagSize(GPBFieldNumber(field)); + if (field.isPackable) { + context->outSize += tagSize; + context->outSize += GPBComputeSizeTSizeAsInt32NoTag(dataSize); + } else { + context->outSize += count * tagSize; + } + } else if (fieldType == GPBFieldTypeSingle) { + BOOL selfHas = GPBGetHasIvarField(context->self, field); + if (selfHas) { + uint64_t selfVal = GPBGetUInt64IvarWithField(context->self, field); + context->outSize += GPBComputeUInt64Size(GPBFieldNumber(field), selfVal); + } + } else { // fieldType == GPBFieldTypeMap + // Type will be GPB*UInt64Dictionary, exact type doesn't matter. + GPBInt32UInt64Dictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += [map computeSerializedSizeAsField:field]; + } + return YES; +} + +//%PDDM-EXPAND SERIALIZED_SIZE_POD_FUNC(Fixed64, uint64_t, UInt64) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicSerializedSizeFixed64(GPBFieldDescriptor *field, + void *voidContext) { + SerializedSizeContext *context = (SerializedSizeContext *)voidContext; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBUInt64Array *array = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + NSUInteger count = array.count; + if (count == 0) return YES; + __block size_t dataSize = 0; + [array enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(idx, stop) + dataSize += GPBComputeFixed64SizeNoTag(value); + }]; + context->outSize += dataSize; + size_t tagSize = GPBComputeTagSize(GPBFieldNumber(field)); + if (field.isPackable) { + context->outSize += tagSize; + context->outSize += GPBComputeSizeTSizeAsInt32NoTag(dataSize); + } else { + context->outSize += count * tagSize; + } + } else if (fieldType == GPBFieldTypeSingle) { + BOOL selfHas = GPBGetHasIvarField(context->self, field); + if (selfHas) { + uint64_t selfVal = GPBGetUInt64IvarWithField(context->self, field); + context->outSize += GPBComputeFixed64Size(GPBFieldNumber(field), selfVal); + } + } else { // fieldType == GPBFieldTypeMap + // Type will be GPB*UInt64Dictionary, exact type doesn't matter. + GPBInt32UInt64Dictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += [map computeSerializedSizeAsField:field]; + } + return YES; +} + +//%PDDM-EXPAND SERIALIZED_SIZE_POD_FUNC(Float, float, Float) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicSerializedSizeFloat(GPBFieldDescriptor *field, + void *voidContext) { + SerializedSizeContext *context = (SerializedSizeContext *)voidContext; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBFloatArray *array = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + NSUInteger count = array.count; + if (count == 0) return YES; + __block size_t dataSize = 0; + [array enumerateValuesWithBlock:^(float value, NSUInteger idx, BOOL *stop) { + #pragma unused(idx, stop) + dataSize += GPBComputeFloatSizeNoTag(value); + }]; + context->outSize += dataSize; + size_t tagSize = GPBComputeTagSize(GPBFieldNumber(field)); + if (field.isPackable) { + context->outSize += tagSize; + context->outSize += GPBComputeSizeTSizeAsInt32NoTag(dataSize); + } else { + context->outSize += count * tagSize; + } + } else if (fieldType == GPBFieldTypeSingle) { + BOOL selfHas = GPBGetHasIvarField(context->self, field); + if (selfHas) { + float selfVal = GPBGetFloatIvarWithField(context->self, field); + context->outSize += GPBComputeFloatSize(GPBFieldNumber(field), selfVal); + } + } else { // fieldType == GPBFieldTypeMap + // Type will be GPB*FloatDictionary, exact type doesn't matter. + GPBInt32FloatDictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += [map computeSerializedSizeAsField:field]; + } + return YES; +} + +//%PDDM-EXPAND SERIALIZED_SIZE_POD_FUNC(Double, double, Double) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicSerializedSizeDouble(GPBFieldDescriptor *field, + void *voidContext) { + SerializedSizeContext *context = (SerializedSizeContext *)voidContext; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + GPBDoubleArray *array = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + NSUInteger count = array.count; + if (count == 0) return YES; + __block size_t dataSize = 0; + [array enumerateValuesWithBlock:^(double value, NSUInteger idx, BOOL *stop) { + #pragma unused(idx, stop) + dataSize += GPBComputeDoubleSizeNoTag(value); + }]; + context->outSize += dataSize; + size_t tagSize = GPBComputeTagSize(GPBFieldNumber(field)); + if (field.isPackable) { + context->outSize += tagSize; + context->outSize += GPBComputeSizeTSizeAsInt32NoTag(dataSize); + } else { + context->outSize += count * tagSize; + } + } else if (fieldType == GPBFieldTypeSingle) { + BOOL selfHas = GPBGetHasIvarField(context->self, field); + if (selfHas) { + double selfVal = GPBGetDoubleIvarWithField(context->self, field); + context->outSize += GPBComputeDoubleSize(GPBFieldNumber(field), selfVal); + } + } else { // fieldType == GPBFieldTypeMap + // Type will be GPB*DoubleDictionary, exact type doesn't matter. + GPBInt32DoubleDictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += [map computeSerializedSizeAsField:field]; + } + return YES; +} + +//%PDDM-EXPAND SERIALIZED_SIZE_OBJECT_FUNC(String) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicSerializedSizeString(GPBFieldDescriptor *field, + void *voidContext) { + SerializedSizeContext *context = (SerializedSizeContext *)voidContext; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + NSArray *array = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + for (id value in array) { + context->outSize += GPBComputeStringSizeNoTag(value); + } + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), + GPBGetFieldType(field)); + context->outSize += array.count * tagSize; + } else if (fieldType == GPBFieldTypeSingle) { + BOOL selfHas = GPBGetHasIvarField(context->self, field); + if (selfHas) { + // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check + // again. + id selfVal = GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += GPBComputeStringSize(GPBFieldNumber(field), selfVal); + } + } else { // fieldType == GPBFieldTypeMap + GPBType mapKeyType = field.mapKeyType; + if (mapKeyType == GPBTypeString) { + // If key type was string, then the map is an NSDictionary. + NSDictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += GPBDictionaryComputeSizeInternalHelper(map, field); + } else { + // Type will be GPB*StringDictionary, exact type doesn't matter. + GPBInt32ObjectDictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += [map computeSerializedSizeAsField:field]; + } + } + return YES; +} + +//%PDDM-EXPAND SERIALIZED_SIZE_OBJECT_FUNC(Data) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicSerializedSizeData(GPBFieldDescriptor *field, + void *voidContext) { + SerializedSizeContext *context = (SerializedSizeContext *)voidContext; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + NSArray *array = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + for (id value in array) { + context->outSize += GPBComputeDataSizeNoTag(value); + } + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), + GPBGetFieldType(field)); + context->outSize += array.count * tagSize; + } else if (fieldType == GPBFieldTypeSingle) { + BOOL selfHas = GPBGetHasIvarField(context->self, field); + if (selfHas) { + // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check + // again. + id selfVal = GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += GPBComputeDataSize(GPBFieldNumber(field), selfVal); + } + } else { // fieldType == GPBFieldTypeMap + GPBType mapKeyType = field.mapKeyType; + if (mapKeyType == GPBTypeString) { + // If key type was string, then the map is an NSDictionary. + NSDictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += GPBDictionaryComputeSizeInternalHelper(map, field); + } else { + // Type will be GPB*DataDictionary, exact type doesn't matter. + GPBInt32ObjectDictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += [map computeSerializedSizeAsField:field]; + } + } + return YES; +} + +//%PDDM-EXPAND SERIALIZED_SIZE_OBJECT_FUNC(Message) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicSerializedSizeMessage(GPBFieldDescriptor *field, + void *voidContext) { + SerializedSizeContext *context = (SerializedSizeContext *)voidContext; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + NSArray *array = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + for (id value in array) { + context->outSize += GPBComputeMessageSizeNoTag(value); + } + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), + GPBGetFieldType(field)); + context->outSize += array.count * tagSize; + } else if (fieldType == GPBFieldTypeSingle) { + BOOL selfHas = GPBGetHasIvarField(context->self, field); + if (selfHas) { + // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check + // again. + id selfVal = GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += GPBComputeMessageSize(GPBFieldNumber(field), selfVal); + } + } else { // fieldType == GPBFieldTypeMap + GPBType mapKeyType = field.mapKeyType; + if (mapKeyType == GPBTypeString) { + // If key type was string, then the map is an NSDictionary. + NSDictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += GPBDictionaryComputeSizeInternalHelper(map, field); + } else { + // Type will be GPB*MessageDictionary, exact type doesn't matter. + GPBInt32ObjectDictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += [map computeSerializedSizeAsField:field]; + } + } + return YES; +} + +//%PDDM-EXPAND SERIALIZED_SIZE_OBJECT_FUNC(Group) +// This block of code is generated, do not edit it directly. + +static BOOL DynamicSerializedSizeGroup(GPBFieldDescriptor *field, + void *voidContext) { + SerializedSizeContext *context = (SerializedSizeContext *)voidContext; + GPBFieldType fieldType = field.fieldType; + if (fieldType == GPBFieldTypeRepeated) { + NSArray *array = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + for (id value in array) { + context->outSize += GPBComputeGroupSizeNoTag(value); + } + size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), + GPBGetFieldType(field)); + context->outSize += array.count * tagSize; + } else if (fieldType == GPBFieldTypeSingle) { + BOOL selfHas = GPBGetHasIvarField(context->self, field); + if (selfHas) { + // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check + // again. + id selfVal = GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += GPBComputeGroupSize(GPBFieldNumber(field), selfVal); + } + } else { // fieldType == GPBFieldTypeMap + GPBType mapKeyType = field.mapKeyType; + if (mapKeyType == GPBTypeString) { + // If key type was string, then the map is an NSDictionary. + NSDictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += GPBDictionaryComputeSizeInternalHelper(map, field); + } else { + // Type will be GPB*GroupDictionary, exact type doesn't matter. + GPBInt32ObjectDictionary *map = + GPBGetObjectIvarWithFieldNoAutocreate(context->self, field); + context->outSize += [map computeSerializedSizeAsField:field]; + } + } + return YES; +} + +//%PDDM-EXPAND-END (18 expansions) + +- (size_t)serializedSize { + // Fields. + SerializedSizeContext context = {self, 0}; + GPBApplyStrictFunctions funcs = + GPBAPPLY_STRICT_FUNCTIONS_INIT(DynamicSerializedSize); + GPBApplyStrictFunctionsToMessageFields(&funcs, self, &context); + // Add any unknown fields. + const GPBDescriptor *descriptor = [self descriptor]; + if (descriptor.wireFormat) { + context.outSize += [unknownFields_ serializedSizeAsMessageSet]; + } else { + context.outSize += [unknownFields_ serializedSize]; + } + // Add any extensions. + for (GPBExtensionField *extension in extensionMap_) { + id value = [extensionMap_ objectForKey:extension]; + context.outSize += [extension computeSerializedSizeIncludingTag:value]; + } + + return context.outSize; +} + +#pragma mark - Resolve Methods Support + +typedef struct IvarAccessorMethodContext { + GPBFileSyntax syntax; + IMP impToAdd; + SEL encodingSelector; +} IvarAccessorMethodContext; + +//%PDDM-DEFINE IVAR_ACCESSOR_FUNC_COMMON(NAME, TYPE, TRUE_NAME) +//%static BOOL IvarGet##NAME(GPBFieldDescriptor *field, void *voidContext) { +//% IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; +//% context->impToAdd = imp_implementationWithBlock(^(id obj) { +//% return GPBGet##TRUE_NAME##IvarWithField(obj, field); +//% }); +//% context->encodingSelector = @selector(get##NAME); +//% return NO; +//%} +//% +//%PDDM-DEFINE IVAR_ACCESSOR_FUNC_OBJECT(NAME, TYPE) +//%IVAR_ACCESSOR_FUNC_COMMON(NAME, TYPE, Object) +//%static BOOL IvarSet##NAME(GPBFieldDescriptor *field, void *voidContext) { +//% IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; +//% // Local for syntax so the block doesn't capture context and use random +//% // memory in the future. +//% const GPBFileSyntax syntax = context->syntax; +//% context->impToAdd = imp_implementationWithBlock(^(id obj, TYPE value) { +//% return GPBSetObjectIvarWithFieldInternal(obj, field, value, syntax); +//% }); +//% context->encodingSelector = @selector(set##NAME:); +//% return NO; +//%} +//% +//%PDDM-DEFINE IVAR_ACCESSOR_FUNC_PER_VERSION(NAME, TYPE) +//%IVAR_ACCESSOR_FUNC_PER_VERSION_ALIASED(NAME, TYPE, NAME) +//%PDDM-DEFINE IVAR_ACCESSOR_FUNC_PER_VERSION_ALIASED(NAME, TYPE, TRUE_NAME) +//%IVAR_ACCESSOR_FUNC_COMMON(NAME, TYPE, TRUE_NAME) +//%static BOOL IvarSet##NAME(GPBFieldDescriptor *field, void *voidContext) { +//% IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; +//% // Local for syntax so the block doesn't capture context and use random +//% // memory in the future. +//% const GPBFileSyntax syntax = context->syntax; +//% context->impToAdd = imp_implementationWithBlock(^(id obj, TYPE value) { +//% return GPBSet##TRUE_NAME##IvarWithFieldInternal(obj, field, value, syntax); +//% }); +//% context->encodingSelector = @selector(set##NAME:); +//% return NO; +//%} +//% +//%PDDM-EXPAND IVAR_ACCESSOR_FUNC_PER_VERSION(Bool, BOOL) +// This block of code is generated, do not edit it directly. + +static BOOL IvarGetBool(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + context->impToAdd = imp_implementationWithBlock(^(id obj) { + return GPBGetBoolIvarWithField(obj, field); + }); + context->encodingSelector = @selector(getBool); + return NO; +} + +static BOOL IvarSetBool(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + // Local for syntax so the block doesn't capture context and use random + // memory in the future. + const GPBFileSyntax syntax = context->syntax; + context->impToAdd = imp_implementationWithBlock(^(id obj, BOOL value) { + return GPBSetBoolIvarWithFieldInternal(obj, field, value, syntax); + }); + context->encodingSelector = @selector(setBool:); + return NO; +} + +//%PDDM-EXPAND IVAR_ACCESSOR_FUNC_PER_VERSION(Int32, int32_t) +// This block of code is generated, do not edit it directly. + +static BOOL IvarGetInt32(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + context->impToAdd = imp_implementationWithBlock(^(id obj) { + return GPBGetInt32IvarWithField(obj, field); + }); + context->encodingSelector = @selector(getInt32); + return NO; +} + +static BOOL IvarSetInt32(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + // Local for syntax so the block doesn't capture context and use random + // memory in the future. + const GPBFileSyntax syntax = context->syntax; + context->impToAdd = imp_implementationWithBlock(^(id obj, int32_t value) { + return GPBSetInt32IvarWithFieldInternal(obj, field, value, syntax); + }); + context->encodingSelector = @selector(setInt32:); + return NO; +} + +//%PDDM-EXPAND IVAR_ACCESSOR_FUNC_PER_VERSION_ALIASED(SInt32, int32_t, Int32) +// This block of code is generated, do not edit it directly. + +static BOOL IvarGetSInt32(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + context->impToAdd = imp_implementationWithBlock(^(id obj) { + return GPBGetInt32IvarWithField(obj, field); + }); + context->encodingSelector = @selector(getSInt32); + return NO; +} + +static BOOL IvarSetSInt32(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + // Local for syntax so the block doesn't capture context and use random + // memory in the future. + const GPBFileSyntax syntax = context->syntax; + context->impToAdd = imp_implementationWithBlock(^(id obj, int32_t value) { + return GPBSetInt32IvarWithFieldInternal(obj, field, value, syntax); + }); + context->encodingSelector = @selector(setSInt32:); + return NO; +} + +//%PDDM-EXPAND IVAR_ACCESSOR_FUNC_PER_VERSION_ALIASED(SFixed32, int32_t, Int32) +// This block of code is generated, do not edit it directly. + +static BOOL IvarGetSFixed32(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + context->impToAdd = imp_implementationWithBlock(^(id obj) { + return GPBGetInt32IvarWithField(obj, field); + }); + context->encodingSelector = @selector(getSFixed32); + return NO; +} + +static BOOL IvarSetSFixed32(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + // Local for syntax so the block doesn't capture context and use random + // memory in the future. + const GPBFileSyntax syntax = context->syntax; + context->impToAdd = imp_implementationWithBlock(^(id obj, int32_t value) { + return GPBSetInt32IvarWithFieldInternal(obj, field, value, syntax); + }); + context->encodingSelector = @selector(setSFixed32:); + return NO; +} + +//%PDDM-EXPAND IVAR_ACCESSOR_FUNC_PER_VERSION(UInt32, uint32_t) +// This block of code is generated, do not edit it directly. + +static BOOL IvarGetUInt32(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + context->impToAdd = imp_implementationWithBlock(^(id obj) { + return GPBGetUInt32IvarWithField(obj, field); + }); + context->encodingSelector = @selector(getUInt32); + return NO; +} + +static BOOL IvarSetUInt32(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + // Local for syntax so the block doesn't capture context and use random + // memory in the future. + const GPBFileSyntax syntax = context->syntax; + context->impToAdd = imp_implementationWithBlock(^(id obj, uint32_t value) { + return GPBSetUInt32IvarWithFieldInternal(obj, field, value, syntax); + }); + context->encodingSelector = @selector(setUInt32:); + return NO; +} + +//%PDDM-EXPAND IVAR_ACCESSOR_FUNC_PER_VERSION_ALIASED(Fixed32, uint32_t, UInt32) +// This block of code is generated, do not edit it directly. + +static BOOL IvarGetFixed32(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + context->impToAdd = imp_implementationWithBlock(^(id obj) { + return GPBGetUInt32IvarWithField(obj, field); + }); + context->encodingSelector = @selector(getFixed32); + return NO; +} + +static BOOL IvarSetFixed32(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + // Local for syntax so the block doesn't capture context and use random + // memory in the future. + const GPBFileSyntax syntax = context->syntax; + context->impToAdd = imp_implementationWithBlock(^(id obj, uint32_t value) { + return GPBSetUInt32IvarWithFieldInternal(obj, field, value, syntax); + }); + context->encodingSelector = @selector(setFixed32:); + return NO; +} + +//%PDDM-EXPAND IVAR_ACCESSOR_FUNC_PER_VERSION(Int64, int64_t) +// This block of code is generated, do not edit it directly. + +static BOOL IvarGetInt64(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + context->impToAdd = imp_implementationWithBlock(^(id obj) { + return GPBGetInt64IvarWithField(obj, field); + }); + context->encodingSelector = @selector(getInt64); + return NO; +} + +static BOOL IvarSetInt64(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + // Local for syntax so the block doesn't capture context and use random + // memory in the future. + const GPBFileSyntax syntax = context->syntax; + context->impToAdd = imp_implementationWithBlock(^(id obj, int64_t value) { + return GPBSetInt64IvarWithFieldInternal(obj, field, value, syntax); + }); + context->encodingSelector = @selector(setInt64:); + return NO; +} + +//%PDDM-EXPAND IVAR_ACCESSOR_FUNC_PER_VERSION_ALIASED(SFixed64, int64_t, Int64) +// This block of code is generated, do not edit it directly. + +static BOOL IvarGetSFixed64(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + context->impToAdd = imp_implementationWithBlock(^(id obj) { + return GPBGetInt64IvarWithField(obj, field); + }); + context->encodingSelector = @selector(getSFixed64); + return NO; +} + +static BOOL IvarSetSFixed64(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + // Local for syntax so the block doesn't capture context and use random + // memory in the future. + const GPBFileSyntax syntax = context->syntax; + context->impToAdd = imp_implementationWithBlock(^(id obj, int64_t value) { + return GPBSetInt64IvarWithFieldInternal(obj, field, value, syntax); + }); + context->encodingSelector = @selector(setSFixed64:); + return NO; +} + +//%PDDM-EXPAND IVAR_ACCESSOR_FUNC_PER_VERSION_ALIASED(SInt64, int64_t, Int64) +// This block of code is generated, do not edit it directly. + +static BOOL IvarGetSInt64(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + context->impToAdd = imp_implementationWithBlock(^(id obj) { + return GPBGetInt64IvarWithField(obj, field); + }); + context->encodingSelector = @selector(getSInt64); + return NO; +} + +static BOOL IvarSetSInt64(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + // Local for syntax so the block doesn't capture context and use random + // memory in the future. + const GPBFileSyntax syntax = context->syntax; + context->impToAdd = imp_implementationWithBlock(^(id obj, int64_t value) { + return GPBSetInt64IvarWithFieldInternal(obj, field, value, syntax); + }); + context->encodingSelector = @selector(setSInt64:); + return NO; +} + +//%PDDM-EXPAND IVAR_ACCESSOR_FUNC_PER_VERSION(UInt64, uint64_t) +// This block of code is generated, do not edit it directly. + +static BOOL IvarGetUInt64(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + context->impToAdd = imp_implementationWithBlock(^(id obj) { + return GPBGetUInt64IvarWithField(obj, field); + }); + context->encodingSelector = @selector(getUInt64); + return NO; +} + +static BOOL IvarSetUInt64(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + // Local for syntax so the block doesn't capture context and use random + // memory in the future. + const GPBFileSyntax syntax = context->syntax; + context->impToAdd = imp_implementationWithBlock(^(id obj, uint64_t value) { + return GPBSetUInt64IvarWithFieldInternal(obj, field, value, syntax); + }); + context->encodingSelector = @selector(setUInt64:); + return NO; +} + +//%PDDM-EXPAND IVAR_ACCESSOR_FUNC_PER_VERSION_ALIASED(Fixed64, uint64_t, UInt64) +// This block of code is generated, do not edit it directly. + +static BOOL IvarGetFixed64(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + context->impToAdd = imp_implementationWithBlock(^(id obj) { + return GPBGetUInt64IvarWithField(obj, field); + }); + context->encodingSelector = @selector(getFixed64); + return NO; +} + +static BOOL IvarSetFixed64(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + // Local for syntax so the block doesn't capture context and use random + // memory in the future. + const GPBFileSyntax syntax = context->syntax; + context->impToAdd = imp_implementationWithBlock(^(id obj, uint64_t value) { + return GPBSetUInt64IvarWithFieldInternal(obj, field, value, syntax); + }); + context->encodingSelector = @selector(setFixed64:); + return NO; +} + +//%PDDM-EXPAND IVAR_ACCESSOR_FUNC_PER_VERSION(Float, float) +// This block of code is generated, do not edit it directly. + +static BOOL IvarGetFloat(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + context->impToAdd = imp_implementationWithBlock(^(id obj) { + return GPBGetFloatIvarWithField(obj, field); + }); + context->encodingSelector = @selector(getFloat); + return NO; +} + +static BOOL IvarSetFloat(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + // Local for syntax so the block doesn't capture context and use random + // memory in the future. + const GPBFileSyntax syntax = context->syntax; + context->impToAdd = imp_implementationWithBlock(^(id obj, float value) { + return GPBSetFloatIvarWithFieldInternal(obj, field, value, syntax); + }); + context->encodingSelector = @selector(setFloat:); + return NO; +} + +//%PDDM-EXPAND IVAR_ACCESSOR_FUNC_PER_VERSION(Double, double) +// This block of code is generated, do not edit it directly. + +static BOOL IvarGetDouble(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + context->impToAdd = imp_implementationWithBlock(^(id obj) { + return GPBGetDoubleIvarWithField(obj, field); + }); + context->encodingSelector = @selector(getDouble); + return NO; +} + +static BOOL IvarSetDouble(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + // Local for syntax so the block doesn't capture context and use random + // memory in the future. + const GPBFileSyntax syntax = context->syntax; + context->impToAdd = imp_implementationWithBlock(^(id obj, double value) { + return GPBSetDoubleIvarWithFieldInternal(obj, field, value, syntax); + }); + context->encodingSelector = @selector(setDouble:); + return NO; +} + +//%PDDM-EXPAND IVAR_ACCESSOR_FUNC_OBJECT(String, id) +// This block of code is generated, do not edit it directly. + +static BOOL IvarGetString(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + context->impToAdd = imp_implementationWithBlock(^(id obj) { + return GPBGetObjectIvarWithField(obj, field); + }); + context->encodingSelector = @selector(getString); + return NO; +} + +static BOOL IvarSetString(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + // Local for syntax so the block doesn't capture context and use random + // memory in the future. + const GPBFileSyntax syntax = context->syntax; + context->impToAdd = imp_implementationWithBlock(^(id obj, id value) { + return GPBSetObjectIvarWithFieldInternal(obj, field, value, syntax); + }); + context->encodingSelector = @selector(setString:); + return NO; +} + +//%PDDM-EXPAND IVAR_ACCESSOR_FUNC_OBJECT(Data, id) +// This block of code is generated, do not edit it directly. + +static BOOL IvarGetData(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + context->impToAdd = imp_implementationWithBlock(^(id obj) { + return GPBGetObjectIvarWithField(obj, field); + }); + context->encodingSelector = @selector(getData); + return NO; +} + +static BOOL IvarSetData(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + // Local for syntax so the block doesn't capture context and use random + // memory in the future. + const GPBFileSyntax syntax = context->syntax; + context->impToAdd = imp_implementationWithBlock(^(id obj, id value) { + return GPBSetObjectIvarWithFieldInternal(obj, field, value, syntax); + }); + context->encodingSelector = @selector(setData:); + return NO; +} + +//%PDDM-EXPAND IVAR_ACCESSOR_FUNC_OBJECT(Message, id) +// This block of code is generated, do not edit it directly. + +static BOOL IvarGetMessage(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + context->impToAdd = imp_implementationWithBlock(^(id obj) { + return GPBGetObjectIvarWithField(obj, field); + }); + context->encodingSelector = @selector(getMessage); + return NO; +} + +static BOOL IvarSetMessage(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + // Local for syntax so the block doesn't capture context and use random + // memory in the future. + const GPBFileSyntax syntax = context->syntax; + context->impToAdd = imp_implementationWithBlock(^(id obj, id value) { + return GPBSetObjectIvarWithFieldInternal(obj, field, value, syntax); + }); + context->encodingSelector = @selector(setMessage:); + return NO; +} + +//%PDDM-EXPAND IVAR_ACCESSOR_FUNC_OBJECT(Group, id) +// This block of code is generated, do not edit it directly. + +static BOOL IvarGetGroup(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + context->impToAdd = imp_implementationWithBlock(^(id obj) { + return GPBGetObjectIvarWithField(obj, field); + }); + context->encodingSelector = @selector(getGroup); + return NO; +} + +static BOOL IvarSetGroup(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + // Local for syntax so the block doesn't capture context and use random + // memory in the future. + const GPBFileSyntax syntax = context->syntax; + context->impToAdd = imp_implementationWithBlock(^(id obj, id value) { + return GPBSetObjectIvarWithFieldInternal(obj, field, value, syntax); + }); + context->encodingSelector = @selector(setGroup:); + return NO; +} + +//%PDDM-EXPAND-END (17 expansions) + +// Enum gets custom hooks because get needs the syntax to Get. + +static BOOL IvarGetEnum(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + // Local for syntax so the block doesn't capture context and use random + // memory in the future. + const GPBFileSyntax syntax = context->syntax; + context->impToAdd = imp_implementationWithBlock(^(id obj) { + return GPBGetEnumIvarWithFieldInternal(obj, field, syntax); + }); + context->encodingSelector = @selector(getEnum); + return NO; +} + +static BOOL IvarSetEnum(GPBFieldDescriptor *field, void *voidContext) { + IvarAccessorMethodContext *context = (IvarAccessorMethodContext *)voidContext; + // Local for syntax so the block doesn't capture context and use random + // memory in the future. + const GPBFileSyntax syntax = context->syntax; + context->impToAdd = imp_implementationWithBlock(^(id obj, int32_t value) { + return GPBSetEnumIvarWithFieldInternal(obj, field, value, syntax); + }); + context->encodingSelector = @selector(setEnum:); + return NO; +} + ++ (BOOL)resolveInstanceMethod:(SEL)sel { + const GPBDescriptor *descriptor = [self descriptor]; + if (!descriptor) { + return NO; + } + + // NOTE: hasSel_/setHasSel_ will be NULL if the field for the given message + // should not have has support (done in GPBDescriptor.m), so there is no need + // for checks here to see if has*/setHas* are allowed. + + IvarAccessorMethodContext context = {descriptor.file.syntax, NULL, NULL}; + for (GPBFieldDescriptor *field in descriptor->fields_) { + BOOL isMapOrArray = GPBFieldIsMapOrArray(field); + if (!isMapOrArray) { + if (sel == field->getSel_) { + static const GPBApplyStrictFunctions funcs = + GPBAPPLY_STRICT_FUNCTIONS_INIT(IvarGet); + funcs[GPBGetFieldType(field)](field, &context); + break; + } else if (sel == field->hasSel_) { + int32_t index = GPBFieldHasIndex(field); + uint32_t fieldNum = GPBFieldNumber(field); + context.impToAdd = imp_implementationWithBlock(^(id obj) { + return GPBGetHasIvar(obj, index, fieldNum); + }); + context.encodingSelector = @selector(getBool); + break; + } else if (sel == field->setHasSel_) { + context.impToAdd = imp_implementationWithBlock(^(id obj, BOOL value) { + if (value) { + [NSException raise:NSInvalidArgumentException + format:@"has fields can only be set to NO"]; + } + GPBClearMessageField(obj, field); + }); + context.encodingSelector = @selector(setBool:); + break; + } else if (sel == field->setSel_) { + GPBApplyStrictFunctions funcs = GPBAPPLY_STRICT_FUNCTIONS_INIT(IvarSet); + funcs[GPBGetFieldType(field)](field, &context); + break; + } else { + GPBOneofDescriptor *oneof = field->containingOneof_; + if (oneof && (sel == oneof->caseSel_)) { + int32_t index = oneof->oneofDescription_->index; + context.impToAdd = imp_implementationWithBlock(^(id obj) { + return GPBGetHasOneof(obj, index); + }); + context.encodingSelector = @selector(getEnum); + break; + } + } + } else { + if (sel == field->getSel_) { + context.impToAdd = imp_implementationWithBlock(^(id obj) { + return GetArrayIvarWithField(obj, field); + }); + context.encodingSelector = @selector(getArray); + break; + } else if (sel == field->setSel_) { + // Local for syntax so the block doesn't capture context and use random + // memory in the future. + const GPBFileSyntax syntax = context.syntax; + context.impToAdd = imp_implementationWithBlock(^(id obj, id value) { + return GPBSetObjectIvarWithFieldInternal(obj, field, value, syntax); + }); + context.encodingSelector = @selector(setArray:); + break; + } + } + } + if (context.impToAdd) { + const char *encoding = + GPBMessageEncodingForSelector(context.encodingSelector, YES); + BOOL methodAdded = class_addMethod(descriptor.messageClass, sel, + context.impToAdd, encoding); + return methodAdded; + } + return [super resolveInstanceMethod:sel]; +} + +#pragma mark - NSCoding Support + +- (instancetype)initWithCoder:(NSCoder *)aDecoder { + self = [self init]; + if (self) { + [self mergeFromData:[aDecoder decodeDataObject] extensionRegistry:nil]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeDataObject:[self data]]; +} + +#pragma mark - KVC Support + ++ (BOOL)accessInstanceVariablesDirectly { + // Make sure KVC doesn't use instance variables. + return NO; +} + +@end diff --git a/objectivec/GPBMessage_PackagePrivate.h b/objectivec/GPBMessage_PackagePrivate.h new file mode 100644 index 00000000..f2a3d5fa --- /dev/null +++ b/objectivec/GPBMessage_PackagePrivate.h @@ -0,0 +1,124 @@ +// 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. + +// This header is private to the ProtobolBuffers library and must NOT be +// included by any sources outside this library. The contents of this file are +// subject to change at any time without notice. + +#import "GPBMessage.h" + +#import <libkern/OSAtomic.h> + +#import "GPBBootstrap.h" + +typedef struct GPBMessage_Storage { + uint32_t _has_storage_[0]; +} GPBMessage_Storage; + +typedef struct GPBMessage_Storage *GPBMessage_StoragePtr; + +@interface GPBMessage () { + @package + // NOTE: Because of the +allocWithZone code using NSAllocateObject(), + // this structure should ideally always be kept pointer aligned where the + // real storage starts is also pointer aligned. The compiler/runtime already + // do this, but it may not be documented. + + // A pointer to the actual fields of the subclasses. The actual structure + // pointed to by this pointer will depend on the subclass. + // All of the actual structures will start the same as + // GPBMessage_Storage with _has_storage__ as the first field. + // Kept public because static functions need to access it. + GPBMessage_StoragePtr messageStorage_; + + // A lock to provide mutual exclusion from internal data that can be modified + // by *read* operations such as getters (autocreation of message fields and + // message extensions, not setting of values). Used to guarantee thread safety + // for concurrent reads on the message. + OSSpinLock readOnlyMutex_; +} + +// Gets an extension value without autocreating the result if not found. (i.e. +// returns nil if the extension is not set) +- (id)getExistingExtension:(GPBExtensionField *)extension; + +// Returns an array of GPBExtensionField* for all the extensions currently +// in use on the message. They are sorted by field number. +- (NSArray *)sortedExtensionsInUse; + +// Parses a message of this type from the input and merges it with this +// message. +// +// Warning: This does not verify that all required fields are present in +// the input message. +// Note: The caller should call +// -[CodedInputStream checkLastTagWas:] after calling this to +// verify that the last tag seen was the appropriate end-group tag, +// or zero for EOF. +- (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input + extensionRegistry:(GPBExtensionRegistry *)extensionRegistry; + +// Parses the next delimited message of this type from the input and merges it +// with this message. +- (void)mergeDelimitedFromCodedInputStream:(GPBCodedInputStream *)input + extensionRegistry: + (GPBExtensionRegistry *)extensionRegistry; + +- (void)addUnknownMapEntry:(int32_t)fieldNum value:(NSData *)data; + +@end + +CF_EXTERN_C_BEGIN + +// Returns a new instance that was automatically created by |autocreator| for +// its field |field|. +GPBMessage *GPBCreateMessageWithAutocreator(Class msgClass, + GPBMessage *autocreator, + GPBFieldDescriptor *field) + __attribute__((ns_returns_retained)); + +// Returns whether |message| autocreated this message. This is NO if the message +// was not autocreated by |message| or if it has been mutated since +// autocreation. +BOOL GPBWasMessageAutocreatedBy(GPBMessage *message, GPBMessage *parent); + +// Call this when you mutate a message. It will cause the message to become +// visible to its autocreator. +void GPBBecomeVisibleToAutocreator(GPBMessage *self); + +// Call this when an array is mutabled so the parent message that autocreated +// it can react. +void GPBAutocreatedArrayModified(GPBMessage *self, id array); + +// Clear the autocreator, if any. Asserts if the autocreator still has an +// autocreated reference to this message. +void GPBClearMessageAutocreator(GPBMessage *self); + +CF_EXTERN_C_END diff --git a/objectivec/GPBProtocolBuffers.h b/objectivec/GPBProtocolBuffers.h new file mode 100644 index 00000000..436c9836 --- /dev/null +++ b/objectivec/GPBProtocolBuffers.h @@ -0,0 +1,45 @@ +// 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. + +#import "GPBBootstrap.h" + +#import "GPBArray.h" +#import "GPBCodedInputStream.h" +#import "GPBCodedOutputStream.h" +#import "GPBDescriptor.h" +#import "GPBDictionary.h" +#import "GPBExtensionField.h" +#import "GPBExtensionRegistry.h" +#import "GPBField.h" +#import "GPBMessage.h" +#import "GPBRootObject.h" +#import "GPBUnknownFieldSet.h" +#import "GPBUtilities.h" +#import "GPBWireFormat.h" diff --git a/objectivec/GPBProtocolBuffers.m b/objectivec/GPBProtocolBuffers.m new file mode 100644 index 00000000..96eeb1d3 --- /dev/null +++ b/objectivec/GPBProtocolBuffers.m @@ -0,0 +1,49 @@ +// 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. + +// If you want to build protocol buffers in your own project without adding the +// project dependency, you can just add this file. + +#import "GPBArray.m" +#import "GPBCodedInputStream.m" +#import "GPBCodedOutputStream.m" +#import "GPBDescriptor.m" +#import "GPBDictionary.m" +#import "GPBExtensionField.m" +#import "GPBExtensionRegistry.m" +#import "GPBField.m" +#import "GPBMessage.m" +#import "GPBRootObject.m" +#import "GPBUnknownFieldSet.m" +#import "GPBUtilities.m" +#import "GPBWellKnownTypes.m" +#import "GPBWireFormat.m" + +#import "google/protobuf/Descriptor.pbobjc.m" diff --git a/objectivec/GPBProtocolBuffers_RuntimeSupport.h b/objectivec/GPBProtocolBuffers_RuntimeSupport.h new file mode 100644 index 00000000..ac3226ef --- /dev/null +++ b/objectivec/GPBProtocolBuffers_RuntimeSupport.h @@ -0,0 +1,41 @@ +// 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. + +// This header is meant to only be used by the generated source, it should not +// be included in code using protocol buffers. + +#import "GPBProtocolBuffers.h" + +#import "GPBDescriptor_PackagePrivate.h" +#import "GPBExtensionField_PackagePrivate.h" +#import "GPBExtensionRegistry_PackagePrivate.h" +#import "GPBMessage_PackagePrivate.h" +#import "GPBRootObject_PackagePrivate.h" +#import "GPBUtilities_PackagePrivate.h" diff --git a/objectivec/GPBRootObject.h b/objectivec/GPBRootObject.h new file mode 100644 index 00000000..2904162e --- /dev/null +++ b/objectivec/GPBRootObject.h @@ -0,0 +1,42 @@ +// 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. + +#import <Foundation/Foundation.h> + +@class GPBExtensionRegistry; + +// All Root Objects derive from GPBRootObject. It supplies a registry +// for derived classes to register their extensions to. +@interface GPBRootObject : NSObject + +// Per class registry. ++ (GPBExtensionRegistry *)extensionRegistry; + +@end diff --git a/objectivec/GPBRootObject.m b/objectivec/GPBRootObject.m new file mode 100644 index 00000000..b58f95ce --- /dev/null +++ b/objectivec/GPBRootObject.m @@ -0,0 +1,177 @@ +// 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. + +#import "GPBRootObject_PackagePrivate.h" + +#import <objc/runtime.h> + +#import <CoreFoundation/CoreFoundation.h> + +#import "GPBDescriptor.h" +#import "GPBExtensionField.h" +#import "GPBUtilities_PackagePrivate.h" + +@interface GPBExtensionDescriptor (GPBRootObject) +// Get singletonName as a c string. +- (const char *)singletonNameC; +@end + +@implementation GPBRootObject + +// Taken from http://www.burtleburtle.net/bob/hash/doobs.html +// Public Domain +static uint32_t jenkins_one_at_a_time_hash(const char *key) { + uint32_t hash = 0; + for (uint32_t i = 0; key[i] != '\0'; ++i) { + hash += key[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return hash; +} + +// Key methods for our custom CFDictionary. +// Note that the dictionary lasts for the lifetime of our app, so no need +// to worry about deallocation. All of the items are added to it at +// startup, and so the keys don't need to be retained/released. +// Keys are NULL terminated char *. +static const void *GPBRootExtensionKeyRetain(CFAllocatorRef allocator, + const void *value) { +#pragma unused(allocator) + return value; +} + +static void GPBRootExtensionKeyRelease(CFAllocatorRef allocator, + const void *value) { +#pragma unused(allocator) +#pragma unused(value) +} + +static CFStringRef GPBRootExtensionCopyKeyDescription(const void *value) { + const char *key = (const char *)value; + return CFStringCreateWithCString(kCFAllocatorDefault, key, + kCFStringEncodingUTF8); +} + +static Boolean GPBRootExtensionKeyEqual(const void *value1, + const void *value2) { + const char *key1 = (const char *)value1; + const char *key2 = (const char *)value2; + return strcmp(key1, key2) == 0; +} + +static CFHashCode GPBRootExtensionKeyHash(const void *value) { + const char *key = (const char *)value; + return jenkins_one_at_a_time_hash(key); +} + +static CFMutableDictionaryRef gExtensionSingletonDictionary = NULL; + ++ (void)initialize { + if (!gExtensionSingletonDictionary) { + CFDictionaryKeyCallBacks keyCallBacks = { + // See description above for reason for using custom dictionary. + 0, + GPBRootExtensionKeyRetain, + GPBRootExtensionKeyRelease, + GPBRootExtensionCopyKeyDescription, + GPBRootExtensionKeyEqual, + GPBRootExtensionKeyHash, + }; + gExtensionSingletonDictionary = + CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &keyCallBacks, + &kCFTypeDictionaryValueCallBacks); + } +} + ++ (GPBExtensionRegistry *)extensionRegistry { + // Is overridden in all the subclasses that provide extensions to provide the + // per class one. + return nil; +} + ++ (void)globallyRegisterExtension:(GPBExtensionField *)field { + const char *key = [field.descriptor singletonNameC]; + // Register happens at startup, so there is no thread safety issue in + // modifying the dictionary. + CFDictionarySetValue(gExtensionSingletonDictionary, key, field); +} + +static id ExtensionForName(id self, SEL _cmd) { + // Really fast way of doing "classname_selName". + // This came up as a hotspot (creation of NSString *) when accessing a + // lot of extensions. + const char *className = class_getName(self); + const char *selName = sel_getName(_cmd); + size_t classNameLen = strlen(className); + size_t selNameLen = strlen(selName); + char key[classNameLen + selNameLen + 2]; + memcpy(key, className, classNameLen); + key[classNameLen] = '_'; + memcpy(&key[classNameLen + 1], selName, selNameLen); + key[classNameLen + 1 + selNameLen] = '\0'; + id extension = (id)CFDictionaryGetValue(gExtensionSingletonDictionary, key); + // We can't remove the key from the dictionary here (as an optimization), + // because resolveClassMethod can happen on any thread and we'd then need + // a lock. + return extension; +} + ++ (BOOL)resolveClassMethod:(SEL)sel { + // Another option would be to register the extensions with the class at + // globallyRegisterExtension: + // Timing the two solutions, this solution turned out to be much faster + // and reduced startup time, and runtime memory. + // On an iPhone 5s: + // ResolveClassMethod: 1515583 nanos + // globallyRegisterExtension: 2453083 nanos + // The advantage to globallyRegisterExtension is that it would reduce the + // size of the protos somewhat because the singletonNameC wouldn't need + // to include the class name. For a class with a lot of extensions it + // can add up. You could also significantly reduce the code complexity of this + // file. + id extension = ExtensionForName(self, sel); + if (extension != nil) { + const char *encoding = + GPBMessageEncodingForSelector(@selector(getClassValue), NO); + Class metaClass = objc_getMetaClass(class_getName(self)); + IMP imp = imp_implementationWithBlock(^(id obj) { +#pragma unused(obj) + return extension; + }); + return class_addMethod(metaClass, sel, imp, encoding); + } + return [super resolveClassMethod:sel]; +} + +@end diff --git a/objectivec/GPBRootObject_PackagePrivate.h b/objectivec/GPBRootObject_PackagePrivate.h new file mode 100644 index 00000000..4e1d3913 --- /dev/null +++ b/objectivec/GPBRootObject_PackagePrivate.h @@ -0,0 +1,42 @@ +// 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. + +#import <Foundation/Foundation.h> + +#import "GPBRootObject.h" + +@class GPBExtensionField; + +@interface GPBRootObject () + +// Globally register. ++ (void)globallyRegisterExtension:(GPBExtensionField *)field; + +@end diff --git a/objectivec/GPBTypes.h b/objectivec/GPBTypes.h new file mode 100644 index 00000000..49c2b9e4 --- /dev/null +++ b/objectivec/GPBTypes.h @@ -0,0 +1,102 @@ +// 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. + +#import <Foundation/Foundation.h> + +#import "GPBBootstrap.h" + +@class GPBEnumDescriptor; +@class GPBMessage; +@class GPBInt32Array; + +// Function used to verify that a given value can be represented by an +// enum type. +typedef BOOL (*GPBEnumValidationFunc)(int32_t); + +// Function used to fetch an EnumDescriptor. +typedef GPBEnumDescriptor *(*GPBEnumDescriptorFunc)(void); + +// Magic values used for when an the at runtime to indicate an enum value +// that wasn't know at compile time. +enum { + kGPBUnrecognizedEnumeratorValue = (int32_t)0xFBADBEEF, +}; + +// A union for storing all possible Protobuf values. +// Note that owner is responsible for memory management of object types. +typedef union { + BOOL valueBool; + int32_t valueInt32; + int64_t valueInt64; + uint32_t valueUInt32; + uint64_t valueUInt64; + float valueFloat; + double valueDouble; + GPB_UNSAFE_UNRETAINED NSData *valueData; + GPB_UNSAFE_UNRETAINED NSString *valueString; + GPB_UNSAFE_UNRETAINED GPBMessage *valueMessage; + int32_t valueEnum; +} GPBValue; + +// Do not change the order of this enum (or add things to it) without thinking +// about it very carefully. There are several things that depend on the order. +typedef enum { + GPBTypeBool = 0, + GPBTypeFixed32, + GPBTypeSFixed32, + GPBTypeFloat, + GPBTypeFixed64, + GPBTypeSFixed64, + GPBTypeDouble, + GPBTypeInt32, + GPBTypeInt64, + GPBTypeSInt32, + GPBTypeSInt64, + GPBTypeUInt32, + GPBTypeUInt64, + GPBTypeData, // Maps to Bytes Protobuf type + GPBTypeString, + GPBTypeMessage, + GPBTypeGroup, + GPBTypeEnum, +} GPBType; + +enum { + // A count of the number of types in GPBType. Separated out from the GPBType + // enum to avoid warnings regarding not handling GPBTypeCount in switch + // statements. + GPBTypeCount = GPBTypeEnum + 1 +}; + +// An extension range. +typedef struct GPBExtensionRange { + uint32_t start; // inclusive + uint32_t end; // exclusive +} GPBExtensionRange; diff --git a/objectivec/GPBUnknownFieldSet.h b/objectivec/GPBUnknownFieldSet.h new file mode 100644 index 00000000..48824f10 --- /dev/null +++ b/objectivec/GPBUnknownFieldSet.h @@ -0,0 +1,46 @@ +// 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. + +#import <Foundation/Foundation.h> + +@class GPBField; + +@interface GPBUnknownFieldSet : NSObject<NSCopying> + +- (BOOL)hasField:(int32_t)number; +- (GPBField *)getField:(int32_t)number; +- (NSUInteger)countOfFields; + +- (void)addField:(GPBField *)field; + +// Returns an NSArray of the GPBFields sorted by the field numbers. +- (NSArray *)sortedFields; + +@end diff --git a/objectivec/GPBUnknownFieldSet.m b/objectivec/GPBUnknownFieldSet.m new file mode 100644 index 00000000..d7154dc8 --- /dev/null +++ b/objectivec/GPBUnknownFieldSet.m @@ -0,0 +1,422 @@ +// 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. + +#import "GPBUnknownFieldSet_PackagePrivate.h" + +#import "GPBCodedInputStream_PackagePrivate.h" +#import "GPBCodedOutputStream.h" +#import "GPBField_PackagePrivate.h" +#import "GPBUtilities.h" +#import "GPBWireFormat.h" + +#pragma mark CFDictionaryKeyCallBacks + +// We use a custom dictionary here because our keys are numbers and +// conversion back and forth from NSNumber was costing us performance. +// If/when we move to C++ this could be done using a std::map and some +// careful retain/release calls. + +static const void *GPBUnknownFieldSetKeyRetain(CFAllocatorRef allocator, + const void *value) { +#pragma unused(allocator) + return value; +} + +static void GPBUnknownFieldSetKeyRelease(CFAllocatorRef allocator, + const void *value) { +#pragma unused(allocator) +#pragma unused(value) +} + +static CFStringRef GPBUnknownFieldSetCopyKeyDescription(const void *value) { + return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d"), + (int)value); +} + +static Boolean GPBUnknownFieldSetKeyEqual(const void *value1, + const void *value2) { + return value1 == value2; +} + +static CFHashCode GPBUnknownFieldSetKeyHash(const void *value) { + return (CFHashCode)value; +} + +#pragma mark Helpers + +static void checkNumber(int32_t number) { + if (number == 0) { + [NSException raise:NSInvalidArgumentException + format:@"Zero is not a valid field number."]; + } +} + +@implementation GPBUnknownFieldSet { + @package + CFMutableDictionaryRef fields_; +} + +static void CopyWorker(const void *key, const void *value, void *context) { +#pragma unused(key) + GPBField *field = value; + GPBUnknownFieldSet *result = context; + + GPBField *copied = [field copy]; + [result addField:copied]; + [copied release]; +} + +- (id)copyWithZone:(NSZone *)zone { + GPBUnknownFieldSet *result = [[GPBUnknownFieldSet allocWithZone:zone] init]; + if (fields_) { + CFDictionaryApplyFunction(fields_, CopyWorker, result); + } + return result; +} + +- (void)dealloc { + if (fields_) { + CFRelease(fields_); + } + [super dealloc]; +} + +- (BOOL)isEqual:(id)object { + BOOL equal = NO; + if ([object isKindOfClass:[GPBUnknownFieldSet class]]) { + GPBUnknownFieldSet *set = (GPBUnknownFieldSet *)object; + if ((fields_ == NULL) && (set->fields_ == NULL)) { + equal = YES; + } else if ((fields_ != NULL) && (set->fields_ != NULL)) { + equal = CFEqual(fields_, set->fields_); + } + } + return equal; +} + +- (NSUInteger)hash { + // Return the hash of the fields dictionary (or just some value). + if (fields_) { + return CFHash(fields_); + } + return (NSUInteger)[GPBUnknownFieldSet class]; +} + +#pragma mark - Public Methods + +- (BOOL)hasField:(int32_t)number { + ssize_t key = number; + return fields_ ? (CFDictionaryGetValue(fields_, (void *)key) != nil) : NO; +} + +- (GPBField *)getField:(int32_t)number { + ssize_t key = number; + GPBField *result = fields_ ? CFDictionaryGetValue(fields_, (void *)key) : nil; + return result; +} + +- (NSUInteger)countOfFields { + return fields_ ? CFDictionaryGetCount(fields_) : 0; +} + +- (NSArray *)sortedFields { + if (!fields_) return nil; + size_t count = CFDictionaryGetCount(fields_); + ssize_t keys[count]; + GPBField *values[count]; + CFDictionaryGetKeysAndValues(fields_, (const void **)keys, + (const void **)values); + struct GPBFieldPair { + ssize_t key; + GPBField *value; + } pairs[count]; + for (size_t i = 0; i < count; ++i) { + pairs[i].key = keys[i]; + pairs[i].value = values[i]; + }; + qsort_b(pairs, count, sizeof(struct GPBFieldPair), + ^(const void *first, const void *second) { + const struct GPBFieldPair *a = first; + const struct GPBFieldPair *b = second; + return (a->key > b->key) ? 1 : ((a->key == b->key) ? 0 : -1); + }); + for (size_t i = 0; i < count; ++i) { + values[i] = pairs[i].value; + }; + return [NSArray arrayWithObjects:values count:count]; +} + +#pragma mark - Internal Methods + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output { + if (!fields_) return; + size_t count = CFDictionaryGetCount(fields_); + ssize_t keys[count]; + GPBField *values[count]; + CFDictionaryGetKeysAndValues(fields_, (const void **)keys, + (const void **)values); + if (count > 1) { + struct GPBFieldPair { + ssize_t key; + GPBField *value; + } pairs[count]; + + for (size_t i = 0; i < count; ++i) { + pairs[i].key = keys[i]; + pairs[i].value = values[i]; + }; + qsort_b(pairs, count, sizeof(struct GPBFieldPair), + ^(const void *first, const void *second) { + const struct GPBFieldPair *a = first; + const struct GPBFieldPair *b = second; + return (a->key > b->key) ? 1 : ((a->key == b->key) ? 0 : -1); + }); + for (size_t i = 0; i < count; ++i) { + GPBField *value = pairs[i].value; + [value writeToOutput:output]; + } + } else { + [values[0] writeToOutput:output]; + } +} + +- (NSString *)description { + NSMutableString *description = [NSMutableString + stringWithFormat:@"<%@ %p>: TextFormat: {\n", [self class], self]; + NSString *textFormat = GPBTextFormatForUnknownFieldSet(self, @" "); + [description appendString:textFormat]; + [description appendString:@"}"]; + return description; +} + +static void GPBUnknownFieldSetSerializedSize(const void *key, const void *value, + void *context) { +#pragma unused(key) + GPBField *field = value; + size_t *result = context; + *result += [field serializedSize]; +} + +- (size_t)serializedSize { + size_t result = 0; + if (fields_) { + CFDictionaryApplyFunction(fields_, GPBUnknownFieldSetSerializedSize, + &result); + } + return result; +} + +static void GPBUnknownFieldSetWriteAsMessageSetTo(const void *key, + const void *value, + void *context) { +#pragma unused(key) + GPBField *field = value; + GPBCodedOutputStream *output = context; + [field writeAsMessageSetExtensionToOutput:output]; +} + +- (void)writeAsMessageSetTo:(GPBCodedOutputStream *)output { + if (fields_) { + CFDictionaryApplyFunction(fields_, GPBUnknownFieldSetWriteAsMessageSetTo, + output); + } +} + +static void GPBUnknownFieldSetSerializedSizeAsMessageSet(const void *key, + const void *value, + void *context) { +#pragma unused(key) + GPBField *field = value; + size_t *result = context; + *result += [field serializedSizeAsMessageSetExtension]; +} + +- (size_t)serializedSizeAsMessageSet { + size_t result = 0; + if (fields_) { + CFDictionaryApplyFunction( + fields_, GPBUnknownFieldSetSerializedSizeAsMessageSet, &result); + } + return result; +} + +- (NSData *)data { + NSMutableData *data = [NSMutableData dataWithLength:self.serializedSize]; + GPBCodedOutputStream *output = + [[GPBCodedOutputStream alloc] initWithData:data]; + [self writeToCodedOutputStream:output]; + [output release]; + return data; +} + ++ (BOOL)isFieldTag:(int32_t)tag { + return GPBWireFormatGetTagWireType(tag) != GPBWireFormatEndGroup; +} + +- (void)addField:(GPBField *)field { + int32_t number = [field number]; + checkNumber(number); + if (!fields_) { + CFDictionaryKeyCallBacks keyCallBacks = { + // See description above for reason for using custom dictionary. + 0, GPBUnknownFieldSetKeyRetain, GPBUnknownFieldSetKeyRelease, + GPBUnknownFieldSetCopyKeyDescription, GPBUnknownFieldSetKeyEqual, + GPBUnknownFieldSetKeyHash, + }; + fields_ = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &keyCallBacks, + &kCFTypeDictionaryValueCallBacks); + } + ssize_t key = number; + CFDictionarySetValue(fields_, (const void *)key, field); +} + +- (GPBField *)mutableFieldForNumber:(int32_t)number create:(BOOL)create { + ssize_t key = number; + GPBField *existing = + fields_ ? CFDictionaryGetValue(fields_, (const void *)key) : nil; + if (!existing && create) { + existing = [[GPBField alloc] initWithNumber:number]; + // This retains existing. + [self addField:existing]; + [existing release]; + } + return existing; +} + +static void GPBUnknownFieldSetMergeUnknownFields(const void *key, + const void *value, + void *context) { +#pragma unused(key) + GPBField *field = value; + GPBUnknownFieldSet *self = context; + + int32_t number = [field number]; + checkNumber(number); + GPBField *oldField = [self mutableFieldForNumber:number create:NO]; + if (oldField) { + [oldField mergeFromField:field]; + } else { + // Merge only comes from GPBMessage's mergeFrom:, so it means we are on + // mutable message and are an mutable instance, so make sure we need + // mutable fields. + GPBField *fieldCopy = [field copy]; + [self addField:fieldCopy]; + [fieldCopy release]; + } +} + +- (void)mergeUnknownFields:(GPBUnknownFieldSet *)other { + if (other && other->fields_) { + CFDictionaryApplyFunction(other->fields_, + GPBUnknownFieldSetMergeUnknownFields, self); + } +} + +- (void)mergeFromData:(NSData *)data { + GPBCodedInputStream *input = [[GPBCodedInputStream alloc] initWithData:data]; + [self mergeFromCodedInputStream:input]; + [input checkLastTagWas:0]; + [input release]; +} + +- (void)mergeVarintField:(int32_t)number value:(int32_t)value { + checkNumber(number); + [[self mutableFieldForNumber:number create:YES] addVarint:value]; +} + +- (BOOL)mergeFieldFrom:(int32_t)tag input:(GPBCodedInputStream *)input { + int32_t number = GPBWireFormatGetTagFieldNumber(tag); + GPBCodedInputStreamState *state = &input->state_; + switch (GPBWireFormatGetTagWireType(tag)) { + case GPBWireFormatVarint: { + GPBField *field = [self mutableFieldForNumber:number create:YES]; + [field addVarint:GPBCodedInputStreamReadInt64(state)]; + return YES; + } + case GPBWireFormatFixed64: { + GPBField *field = [self mutableFieldForNumber:number create:YES]; + [field addFixed64:GPBCodedInputStreamReadFixed64(state)]; + return YES; + } + case GPBWireFormatLengthDelimited: { + NSData *data = GPBCodedInputStreamReadRetainedData(state); + GPBField *field = [self mutableFieldForNumber:number create:YES]; + [field addLengthDelimited:data]; + [data release]; + return YES; + } + case GPBWireFormatStartGroup: { + GPBUnknownFieldSet *unknownFieldSet = [[GPBUnknownFieldSet alloc] init]; + [input readUnknownGroup:number message:unknownFieldSet]; + GPBField *field = [self mutableFieldForNumber:number create:YES]; + [field addGroup:unknownFieldSet]; + [unknownFieldSet release]; + return YES; + } + case GPBWireFormatEndGroup: + return NO; + case GPBWireFormatFixed32: { + GPBField *field = [self mutableFieldForNumber:number create:YES]; + [field addFixed32:GPBCodedInputStreamReadFixed32(state)]; + return YES; + } + } +} + +- (void)mergeMessageSetMessage:(int32_t)number data:(NSData *)messageData { + [[self mutableFieldForNumber:number create:YES] + addLengthDelimited:messageData]; +} + +- (void)addUnknownMapEntry:(int32_t)fieldNum value:(NSData *)data { + GPBField *field = [self mutableFieldForNumber:fieldNum create:YES]; + [field addLengthDelimited:data]; +} + +- (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input { + while (YES) { + int32_t tag = GPBCodedInputStreamReadTag(&input->state_); + if (tag == 0 || ![self mergeFieldFrom:tag input:input]) { + break; + } + } +} + +- (void)getTags:(int32_t *)tags { + if (!fields_) return; + size_t count = CFDictionaryGetCount(fields_); + ssize_t keys[count]; + CFDictionaryGetKeysAndValues(fields_, (const void **)keys, NULL); + for (size_t i = 0; i < count; ++i) { + tags[i] = (int32_t)keys[i]; + } +} + +@end diff --git a/objectivec/GPBUnknownFieldSet_PackagePrivate.h b/objectivec/GPBUnknownFieldSet_PackagePrivate.h new file mode 100644 index 00000000..e27127ad --- /dev/null +++ b/objectivec/GPBUnknownFieldSet_PackagePrivate.h @@ -0,0 +1,61 @@ +// 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. + +#import <Foundation/Foundation.h> + +#import "GPBUnknownFieldSet.h" + +@class GPBCodedOutputStream; +@class GPBCodedInputStream; + +@interface GPBUnknownFieldSet () + ++ (BOOL)isFieldTag:(int32_t)tag; + +- (NSData *)data; + +- (size_t)serializedSize; +- (size_t)serializedSizeAsMessageSet; + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output; +- (void)writeAsMessageSetTo:(GPBCodedOutputStream *)output; + +- (void)mergeUnknownFields:(GPBUnknownFieldSet *)other; + +- (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input; +- (void)mergeFromData:(NSData *)data; + +- (void)mergeVarintField:(int32_t)number value:(int32_t)value; +- (BOOL)mergeFieldFrom:(int32_t)tag input:(GPBCodedInputStream *)input; +- (void)mergeMessageSetMessage:(int32_t)number data:(NSData *)messageData; + +- (void)addUnknownMapEntry:(int32_t)fieldNum value:(NSData *)data; + +@end diff --git a/objectivec/GPBUtilities.h b/objectivec/GPBUtilities.h new file mode 100644 index 00000000..8813f1ad --- /dev/null +++ b/objectivec/GPBUtilities.h @@ -0,0 +1,181 @@ +// 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. + +#import <Foundation/Foundation.h> + +#import "GPBMessage.h" +#import "GPBTypes.h" + +CF_EXTERN_C_BEGIN + +BOOL GPBMessageHasFieldNumberSet(GPBMessage *self, uint32_t fieldNumber); +BOOL GPBMessageHasFieldSet(GPBMessage *self, GPBFieldDescriptor *field); + +void GPBClearMessageField(GPBMessage *self, GPBFieldDescriptor *field); + +// Returns an empty NSData to assign to byte fields when you wish +// to assign them to empty. Prevents allocating a lot of little [NSData data] +// objects. +NSData *GPBEmptyNSData(void) __attribute__((pure)); + +//%PDDM-EXPAND GPB_IVAR_ACCESSORS() +// This block of code is generated, do not edit it directly. + +// Getters and Setters for ivars named |name| from instance self. + +NSData* GPBGetDataIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field); +void GPBSetDataIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + NSData* value); +NSString* GPBGetStringIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field); +void GPBSetStringIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + NSString* value); +GPBMessage* GPBGetMessageIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field); +void GPBSetMessageIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + GPBMessage* value); +GPBMessage* GPBGetGroupIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field); +void GPBSetGroupIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + GPBMessage* value); +BOOL GPBGetBoolIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field); +void GPBSetBoolIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + BOOL value); +int32_t GPBGetInt32IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field); +void GPBSetInt32IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + int32_t value); +int32_t GPBGetSFixed32IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field); +void GPBSetSFixed32IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + int32_t value); +int32_t GPBGetSInt32IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field); +void GPBSetSInt32IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + int32_t value); +int32_t GPBGetEnumIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field); +void GPBSetEnumIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + int32_t value); +uint32_t GPBGetUInt32IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field); +void GPBSetUInt32IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + uint32_t value); +uint32_t GPBGetFixed32IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field); +void GPBSetFixed32IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + uint32_t value); +int64_t GPBGetInt64IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field); +void GPBSetInt64IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + int64_t value); +int64_t GPBGetSInt64IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field); +void GPBSetSInt64IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + int64_t value); +int64_t GPBGetSFixed64IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field); +void GPBSetSFixed64IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + int64_t value); +uint64_t GPBGetUInt64IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field); +void GPBSetUInt64IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + uint64_t value); +uint64_t GPBGetFixed64IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field); +void GPBSetFixed64IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + uint64_t value); +float GPBGetFloatIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field); +void GPBSetFloatIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + float value); +double GPBGetDoubleIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field); +void GPBSetDoubleIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + double value); +//%PDDM-EXPAND-END GPB_IVAR_ACCESSORS() + +// Generates a sting that should be a valid "Text Format" for the C++ version +// of Protocol Buffers. lineIndent can be nil if no additional line indent is +// needed. The comments provide the names according to the ObjC library, they +// most likely won't exactly match the original .proto file. +NSString *GPBTextFormatForMessage(GPBMessage *message, NSString *lineIndent); +NSString *GPBTextFormatForUnknownFieldSet(GPBUnknownFieldSet *unknownSet, + NSString *lineIndent); + +CF_EXTERN_C_END + +//%PDDM-DEFINE GPB_IVAR_ACCESSORS() +//%// Getters and Setters for ivars named |name| from instance self. +//% +//%GPB_IVAR_ACCESSORS_DECL(Data, NSData*) +//%GPB_IVAR_ACCESSORS_DECL(String, NSString*) +//%GPB_IVAR_ACCESSORS_DECL(Message, GPBMessage*) +//%GPB_IVAR_ACCESSORS_DECL(Group, GPBMessage*) +//%GPB_IVAR_ACCESSORS_DECL(Bool, BOOL) +//%GPB_IVAR_ACCESSORS_DECL(Int32, int32_t) +//%GPB_IVAR_ACCESSORS_DECL(SFixed32, int32_t) +//%GPB_IVAR_ACCESSORS_DECL(SInt32, int32_t) +//%GPB_IVAR_ACCESSORS_DECL(Enum, int32_t) +//%GPB_IVAR_ACCESSORS_DECL(UInt32, uint32_t) +//%GPB_IVAR_ACCESSORS_DECL(Fixed32, uint32_t) +//%GPB_IVAR_ACCESSORS_DECL(Int64, int64_t) +//%GPB_IVAR_ACCESSORS_DECL(SInt64, int64_t) +//%GPB_IVAR_ACCESSORS_DECL(SFixed64, int64_t) +//%GPB_IVAR_ACCESSORS_DECL(UInt64, uint64_t) +//%GPB_IVAR_ACCESSORS_DECL(Fixed64, uint64_t) +//%GPB_IVAR_ACCESSORS_DECL(Float, float) +//%GPB_IVAR_ACCESSORS_DECL(Double, double) +//%PDDM-DEFINE GPB_IVAR_ACCESSORS_DECL(NAME, TYPE) +//%TYPE GPBGet##NAME##IvarWithField(GPBMessage *self, +//% TYPE$S NAME$S GPBFieldDescriptor *field); +//%void GPBSet##NAME##IvarWithField(GPBMessage *self, +//% NAME$S GPBFieldDescriptor *field, +//% NAME$S TYPE value); diff --git a/objectivec/GPBUtilities.m b/objectivec/GPBUtilities.m new file mode 100644 index 00000000..09e34bfb --- /dev/null +++ b/objectivec/GPBUtilities.m @@ -0,0 +1,1645 @@ +// 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. + +#import "GPBUtilities_PackagePrivate.h" + +#import <objc/runtime.h> + +#import "GPBArray_PackagePrivate.h" +#import "GPBDescriptor_PackagePrivate.h" +#import "GPBDictionary_PackagePrivate.h" +#import "GPBExtensionField.h" +#import "GPBField.h" +#import "GPBMessage_PackagePrivate.h" +#import "GPBUnknownFieldSet.h" + +static void AppendTextFormatForMessage(GPBMessage *message, + NSMutableString *toStr, + NSString *lineIndent); + +NSData *GPBEmptyNSData(void) { + static dispatch_once_t onceToken; + static NSData *defaultNSData = nil; + dispatch_once(&onceToken, ^{ + defaultNSData = [[NSData alloc] init]; + }); + return defaultNSData; +} + +BOOL GPBMessageHasFieldNumberSet(GPBMessage *self, uint32_t fieldNumber) { + GPBDescriptor *descriptor = [self descriptor]; + GPBFieldDescriptor *field = [descriptor fieldWithNumber:fieldNumber]; + return GPBMessageHasFieldSet(self, field); +} + +BOOL GPBMessageHasFieldSet(GPBMessage *self, GPBFieldDescriptor *field) { + if (self == nil || field == nil) return NO; + + // Repeated/Map don't use the bit, they check the count. + if (GPBFieldIsMapOrArray(field)) { + // Array/map type doesn't matter, since GPB*Array/NSArray and + // GPB*Dictionary/NSDictionary all support -count; + NSArray *arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + return (arrayOrMap.count > 0); + } else { + return GPBGetHasIvarField(self, field); + } +} + +void GPBClearMessageField(GPBMessage *self, GPBFieldDescriptor *field) { + // If not set, nothing to do. + if (!GPBGetHasIvarField(self, field)) { + return; + } + + if (GPBFieldStoresObject(field)) { + // Object types are handled slightly differently, they need to be released. + uint8_t *storage = (uint8_t *)self->messageStorage_; + id *typePtr = (id *)&storage[field->description_->offset]; + [*typePtr release]; + *typePtr = nil; + } else { + // POD types just need to clear the has bit as the Get* method will + // fetch the default when needed. + } + GPBSetHasIvarField(self, field, NO); +} + +BOOL GPBGetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber) { + NSCAssert(self->messageStorage_ != NULL, @"How?"); + if (idx < 0) { + NSCAssert(fieldNumber != 0, @"Invalid field number."); + BOOL hasIvar = (self->messageStorage_->_has_storage_[-idx] == fieldNumber); + return hasIvar; + } else { + NSCAssert(idx != GPBNoHasBit, @"Invalid has bit."); + uint32_t byteIndex = idx / 32; + uint32_t bitMask = (1 << (idx % 32)); + BOOL hasIvar = + (self->messageStorage_->_has_storage_[byteIndex] & bitMask) ? YES : NO; + return hasIvar; + } +} + +uint32_t GPBGetHasOneof(GPBMessage *self, int32_t idx) { + NSCAssert(idx < 0, @"invalid index for oneof."); + uint32_t result = self->messageStorage_->_has_storage_[-idx]; + return result; +} + +void GPBSetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber, + BOOL value) { + if (idx < 0) { + NSCAssert(fieldNumber != 0, @"Invalid field number."); + uint32_t *has_storage = self->messageStorage_->_has_storage_; + has_storage[-idx] = (value ? fieldNumber : 0); + } else { + NSCAssert(idx != GPBNoHasBit, @"Invalid has bit."); + uint32_t *has_storage = self->messageStorage_->_has_storage_; + uint32_t byte = idx / 32; + uint32_t bitMask = (1 << (idx % 32)); + if (value) { + has_storage[byte] |= bitMask; + } else { + has_storage[byte] &= ~bitMask; + } + } +} + +void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof, + uint32_t fieldNumberNotToClear) { + int32_t hasIndex = oneof->oneofDescription_->index; + uint32_t fieldNumberSet = GPBGetHasOneof(self, hasIndex); + if ((fieldNumberSet == fieldNumberNotToClear) || (fieldNumberSet == 0)) { + // Do nothing/nothing set in the oneof. + return; + } + + // Like GPBClearMessageField(), free the memory if an objecttype is set, + // pod types don't need to do anything. + GPBFieldDescriptor *fieldSet = [oneof fieldWithNumber:fieldNumberSet]; + NSCAssert(fieldSet, @"oneof set to something not in the oneof?"); + if (fieldSet && GPBFieldStoresObject(fieldSet)) { + uint8_t *storage = (uint8_t *)self->messageStorage_; + id *typePtr = (id *)&storage[fieldSet->description_->offset]; + [*typePtr release]; + *typePtr = nil; + } + + // Set to nothing stored in the oneof. + // (field number doesn't matter since setting to nothing). + GPBSetHasIvar(self, hasIndex, 1, NO); +} + +#pragma mark - IVar accessors + +//%PDDM-DEFINE IVAR_POD_ACCESSORS_DEFN(NAME, TYPE) +//%TYPE GPBGet##NAME##IvarWithField(GPBMessage *self, +//% TYPE$S NAME$S GPBFieldDescriptor *field) { +//% if (GPBGetHasIvarField(self, field)) { +//% uint8_t *storage = (uint8_t *)self->messageStorage_; +//% TYPE *typePtr = (TYPE *)&storage[field->description_->offset]; +//% return *typePtr; +//% } else { +//% return field.defaultValue.value##NAME; +//% } +//%} +//% +//%// Only exists for public api, no core code should use this. +//%void GPBSet##NAME##IvarWithField(GPBMessage *self, +//% NAME$S GPBFieldDescriptor *field, +//% NAME$S TYPE value) { +//% if (self == nil || field == nil) return; +//% GPBFileSyntax syntax = [self descriptor].file.syntax; +//% GPBSet##NAME##IvarWithFieldInternal(self, field, value, syntax); +//%} +//% +//%void GPBSet##NAME##IvarWithFieldInternal(GPBMessage *self, +//% NAME$S GPBFieldDescriptor *field, +//% NAME$S TYPE value, +//% NAME$S GPBFileSyntax syntax) { +//% GPBOneofDescriptor *oneof = field->containingOneof_; +//% if (oneof) { +//% GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field)); +//% } +//% NSCAssert(self->messageStorage_ != NULL, @"How?"); +//%#if defined(__clang_analyzer__) +//% if (self->messageStorage_ == NULL) return; +//%#endif +//% uint8_t *storage = (uint8_t *)self->messageStorage_; +//% TYPE *typePtr = (TYPE *)&storage[field->description_->offset]; +//% *typePtr = value; +//% // proto2: any value counts as having been set; proto3, it +//% // has to be a non zero value. +//% BOOL hasValue = +//% (syntax == GPBFileSyntaxProto2) || (value != (TYPE)0); +//% GPBSetHasIvarField(self, field, hasValue); +//% GPBBecomeVisibleToAutocreator(self); +//%} +//% +//%PDDM-DEFINE IVAR_ALIAS_DEFN(NAME, ALIAS_NAME, TYPE, ALIAS_TYPE) +//%// Only exists for public api, no core code should use this. +//%TYPE GPBGet##NAME##IvarWithField(GPBMessage *self, +//% TYPE$S NAME$S GPBFieldDescriptor *field) { +//% return (TYPE)GPBGet##ALIAS_NAME##IvarWithField(self, field); +//%} +//% +//%// Only exists for public api, no core code should use this. +//%void GPBSet##NAME##IvarWithField(GPBMessage *self, +//% NAME$S GPBFieldDescriptor *field, +//% NAME$S TYPE value) { +//% GPBSet##ALIAS_NAME##IvarWithField(self, field, (ALIAS_TYPE)value); +//%} +//% + +// Object types are handled slightly differently, they need to be released +// and retained. + +void GPBSetAutocreatedRetainedObjectIvarWithField( + GPBMessage *self, GPBFieldDescriptor *field, + id __attribute__((ns_consumed)) value) { + uint8_t *storage = (uint8_t *)self->messageStorage_; + id *typePtr = (id *)&storage[field->description_->offset]; + NSCAssert(*typePtr == NULL, @"Can't set autocreated object more than once."); + *typePtr = value; +} + +void GPBClearAutocreatedMessageIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field) { + if (GPBGetHasIvarField(self, field)) { + return; + } + uint8_t *storage = (uint8_t *)self->messageStorage_; + id *typePtr = (id *)&storage[field->description_->offset]; + GPBMessage *oldValue = *typePtr; + *typePtr = NULL; + GPBClearMessageAutocreator(oldValue); + [oldValue release]; +} + +// This exists only for briging some aliased types, nothing else should use it. +GPB_INLINE void GPBSetObjectIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, id value) { + if (self == nil || field == nil) return; + GPBFileSyntax syntax = [self descriptor].file.syntax; + GPBSetRetainedObjectIvarWithFieldInternal(self, field, [value retain], + syntax); +} + +void GPBSetObjectIvarWithFieldInternal(GPBMessage *self, + GPBFieldDescriptor *field, id value, + GPBFileSyntax syntax) { + GPBSetRetainedObjectIvarWithFieldInternal(self, field, [value retain], + syntax); +} + +void GPBSetRetainedObjectIvarWithFieldInternal(GPBMessage *self, + GPBFieldDescriptor *field, + id value, GPBFileSyntax syntax) { + NSCAssert(self->messageStorage_ != NULL, @"How?"); +#if defined(__clang_analyzer__) + if (self->messageStorage_ == NULL) return; +#endif + GPBType fieldType = GPBGetFieldType(field); + BOOL isMapOrArray = GPBFieldIsMapOrArray(field); + BOOL fieldIsMessage = GPBTypeIsMessage(fieldType); +#ifdef DEBUG + if (value == nil && !isMapOrArray && !fieldIsMessage && + field.hasDefaultValue) { + // Setting a message to nil is an obvious way to "clear" the value + // as there is no way to set a non-empty default value for messages. + // + // For Strings and Bytes that have default values set it is not clear what + // should be done when their value is set to nil. Is the intention just to + // clear the set value and reset to default, or is the intention to set the + // value to the empty string/data? Arguments can be made for both cases. + // 'nil' has been abused as a replacement for an empty string/data in ObjC. + // We decided to be consistent with all "object" types and clear the has + // field, and fall back on the default value. The warning below will only + // appear in debug, but the could should be changed so the intention is + // clear. + NSString *hasSel = NSStringFromSelector(field->hasSel_); + NSString *propName = field.name; + NSString *className = self.descriptor.name; + NSLog(@"warning: '%@.%@ = nil;' is not clearly defined for fields with " + @"default values. Please use '%@.%@ = %@' if you want to set it to " + @"empty, or call '%@.%@ = NO' to reset it to it's default value of " + @"'%@'. Defaulting to resetting default value.", + className, propName, className, propName, + (fieldType == GPBTypeString) ? @"@\"\"" : @"GPBEmptyNSData()", + className, hasSel, field.defaultValue.valueString); + // Note: valueString, depending on the type, it could easily be + // valueData/valueMessage. + } +#endif // DEBUG + if (!isMapOrArray) { + // Non repeated/map can be in an oneof, clear any existing value from the + // oneof. + GPBOneofDescriptor *oneof = field->containingOneof_; + if (oneof) { + GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field)); + } + // Clear "has" if they are being set to nil. + BOOL setHasValue = (value != nil); + // Under proto3, Data & String fields get cleared by resetting them to their + // default (empty) values, so if they are set to something of length zero, + // they are being cleared. + if ((syntax == GPBFileSyntaxProto3) && !fieldIsMessage && + ([value length] == 0)) { + setHasValue = NO; + value = nil; + } + GPBSetHasIvarField(self, field, setHasValue); + } + uint8_t *storage = (uint8_t *)self->messageStorage_; + id *typePtr = (id *)&storage[field->description_->offset]; + + id oldValue = *typePtr; + + *typePtr = value; + + if (oldValue) { + if (isMapOrArray) { + if (field.fieldType == GPBFieldTypeRepeated) { + // If the old message value was autocreated by us, then clear it. + if (GPBTypeIsObject(fieldType)) { + GPBAutocreatedArray *autoArray = oldValue; + if (autoArray->_autocreator == self) { + autoArray->_autocreator = nil; + } + } else { + // Type doesn't matter, it is a GPB*Array. + GPBInt32Array *gpbArray = oldValue; + if (gpbArray->_autocreator == self) { + gpbArray->_autocreator = nil; + } + } + } + } else if (fieldIsMessage) { + // If the old message value was autocreated by us, then clear it. + GPBMessage *oldMessageValue = oldValue; + if (GPBWasMessageAutocreatedBy(oldMessageValue, self)) { + GPBClearMessageAutocreator(oldMessageValue); + } + } + [oldValue release]; + } + + GPBBecomeVisibleToAutocreator(self); +} + +id GPBGetObjectIvarWithFieldNoAutocreate(GPBMessage *self, + GPBFieldDescriptor *field) { + if (self->messageStorage_ == nil) { + return nil; + } + uint8_t *storage = (uint8_t *)self->messageStorage_; + id *typePtr = (id *)&storage[field->description_->offset]; + return *typePtr; +} + +id GPBGetObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) { + NSCAssert(!GPBFieldIsMapOrArray(field), @"Shouldn't get here"); + if (GPBGetHasIvarField(self, field)) { + uint8_t *storage = (uint8_t *)self->messageStorage_; + id *typePtr = (id *)&storage[field->description_->offset]; + return *typePtr; + } + // Not set... + + // Non messages (string/data), get their default. + if (!GPBFieldTypeIsMessage(field)) { + return field.defaultValue.valueMessage; + } + + OSSpinLockLock(&self->readOnlyMutex_); + GPBMessage *result = GPBGetObjectIvarWithFieldNoAutocreate(self, field); + if (!result) { + // For non repeated messages, create the object, set it and return it. + // This object will not initially be visible via GPBGetHasIvar, so + // we save its creator so it can become visible if it's mutated later. + result = GPBCreateMessageWithAutocreator(field.msgClass, self, field); + GPBSetAutocreatedRetainedObjectIvarWithField(self, field, result); + } + OSSpinLockUnlock(&self->readOnlyMutex_); + return result; +} + +// Only exists for public api, no core code should use this. +int32_t GPBGetEnumIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) { + GPBFileSyntax syntax = [self descriptor].file.syntax; + return GPBGetEnumIvarWithFieldInternal(self, field, syntax); +} + +int32_t GPBGetEnumIvarWithFieldInternal(GPBMessage *self, + GPBFieldDescriptor *field, + GPBFileSyntax syntax) { + int32_t result = GPBGetInt32IvarWithField(self, field); + // If this is presevering unknown enums, make sure the value is + // valid before returning it. + if (GPBHasPreservingUnknownEnumSemantics(syntax) && + ![field isValidEnumValue:result]) { + result = kGPBUnrecognizedEnumeratorValue; + } + return result; +} + +// Only exists for public api, no core code should use this. +void GPBSetEnumIvarWithField(GPBMessage *self, GPBFieldDescriptor *field, + int32_t value) { + GPBFileSyntax syntax = [self descriptor].file.syntax; + GPBSetInt32IvarWithFieldInternal(self, field, value, syntax); +} + +void GPBSetEnumIvarWithFieldInternal(GPBMessage *self, + GPBFieldDescriptor *field, int32_t value, + GPBFileSyntax syntax) { + // Don't allow in unknown values. Proto3 can use the Raw method. + if (![field isValidEnumValue:value]) { + [NSException raise:NSInvalidArgumentException + format:@"%@.%@: Attempt to set an unknown enum value (%d)", + [self class], field.name, value]; + } + GPBSetInt32IvarWithFieldInternal(self, field, value, syntax); +} + +//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Bool, BOOL) +// This block of code is generated, do not edit it directly. + +BOOL GPBGetBoolIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field) { + if (GPBGetHasIvarField(self, field)) { + uint8_t *storage = (uint8_t *)self->messageStorage_; + BOOL *typePtr = (BOOL *)&storage[field->description_->offset]; + return *typePtr; + } else { + return field.defaultValue.valueBool; + } +} + +// Only exists for public api, no core code should use this. +void GPBSetBoolIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + BOOL value) { + if (self == nil || field == nil) return; + GPBFileSyntax syntax = [self descriptor].file.syntax; + GPBSetBoolIvarWithFieldInternal(self, field, value, syntax); +} + +void GPBSetBoolIvarWithFieldInternal(GPBMessage *self, + GPBFieldDescriptor *field, + BOOL value, + GPBFileSyntax syntax) { + GPBOneofDescriptor *oneof = field->containingOneof_; + if (oneof) { + GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field)); + } + NSCAssert(self->messageStorage_ != NULL, @"How?"); +#if defined(__clang_analyzer__) + if (self->messageStorage_ == NULL) return; +#endif + uint8_t *storage = (uint8_t *)self->messageStorage_; + BOOL *typePtr = (BOOL *)&storage[field->description_->offset]; + *typePtr = value; + // proto2: any value counts as having been set; proto3, it + // has to be a non zero value. + BOOL hasValue = + (syntax == GPBFileSyntaxProto2) || (value != (BOOL)0); + GPBSetHasIvarField(self, field, hasValue); + GPBBecomeVisibleToAutocreator(self); +} + +//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Int32, int32_t) +// This block of code is generated, do not edit it directly. + +int32_t GPBGetInt32IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field) { + if (GPBGetHasIvarField(self, field)) { + uint8_t *storage = (uint8_t *)self->messageStorage_; + int32_t *typePtr = (int32_t *)&storage[field->description_->offset]; + return *typePtr; + } else { + return field.defaultValue.valueInt32; + } +} + +// Only exists for public api, no core code should use this. +void GPBSetInt32IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + int32_t value) { + if (self == nil || field == nil) return; + GPBFileSyntax syntax = [self descriptor].file.syntax; + GPBSetInt32IvarWithFieldInternal(self, field, value, syntax); +} + +void GPBSetInt32IvarWithFieldInternal(GPBMessage *self, + GPBFieldDescriptor *field, + int32_t value, + GPBFileSyntax syntax) { + GPBOneofDescriptor *oneof = field->containingOneof_; + if (oneof) { + GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field)); + } + NSCAssert(self->messageStorage_ != NULL, @"How?"); +#if defined(__clang_analyzer__) + if (self->messageStorage_ == NULL) return; +#endif + uint8_t *storage = (uint8_t *)self->messageStorage_; + int32_t *typePtr = (int32_t *)&storage[field->description_->offset]; + *typePtr = value; + // proto2: any value counts as having been set; proto3, it + // has to be a non zero value. + BOOL hasValue = + (syntax == GPBFileSyntaxProto2) || (value != (int32_t)0); + GPBSetHasIvarField(self, field, hasValue); + GPBBecomeVisibleToAutocreator(self); +} + +//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(UInt32, uint32_t) +// This block of code is generated, do not edit it directly. + +uint32_t GPBGetUInt32IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field) { + if (GPBGetHasIvarField(self, field)) { + uint8_t *storage = (uint8_t *)self->messageStorage_; + uint32_t *typePtr = (uint32_t *)&storage[field->description_->offset]; + return *typePtr; + } else { + return field.defaultValue.valueUInt32; + } +} + +// Only exists for public api, no core code should use this. +void GPBSetUInt32IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + uint32_t value) { + if (self == nil || field == nil) return; + GPBFileSyntax syntax = [self descriptor].file.syntax; + GPBSetUInt32IvarWithFieldInternal(self, field, value, syntax); +} + +void GPBSetUInt32IvarWithFieldInternal(GPBMessage *self, + GPBFieldDescriptor *field, + uint32_t value, + GPBFileSyntax syntax) { + GPBOneofDescriptor *oneof = field->containingOneof_; + if (oneof) { + GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field)); + } + NSCAssert(self->messageStorage_ != NULL, @"How?"); +#if defined(__clang_analyzer__) + if (self->messageStorage_ == NULL) return; +#endif + uint8_t *storage = (uint8_t *)self->messageStorage_; + uint32_t *typePtr = (uint32_t *)&storage[field->description_->offset]; + *typePtr = value; + // proto2: any value counts as having been set; proto3, it + // has to be a non zero value. + BOOL hasValue = + (syntax == GPBFileSyntaxProto2) || (value != (uint32_t)0); + GPBSetHasIvarField(self, field, hasValue); + GPBBecomeVisibleToAutocreator(self); +} + +//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Int64, int64_t) +// This block of code is generated, do not edit it directly. + +int64_t GPBGetInt64IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field) { + if (GPBGetHasIvarField(self, field)) { + uint8_t *storage = (uint8_t *)self->messageStorage_; + int64_t *typePtr = (int64_t *)&storage[field->description_->offset]; + return *typePtr; + } else { + return field.defaultValue.valueInt64; + } +} + +// Only exists for public api, no core code should use this. +void GPBSetInt64IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + int64_t value) { + if (self == nil || field == nil) return; + GPBFileSyntax syntax = [self descriptor].file.syntax; + GPBSetInt64IvarWithFieldInternal(self, field, value, syntax); +} + +void GPBSetInt64IvarWithFieldInternal(GPBMessage *self, + GPBFieldDescriptor *field, + int64_t value, + GPBFileSyntax syntax) { + GPBOneofDescriptor *oneof = field->containingOneof_; + if (oneof) { + GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field)); + } + NSCAssert(self->messageStorage_ != NULL, @"How?"); +#if defined(__clang_analyzer__) + if (self->messageStorage_ == NULL) return; +#endif + uint8_t *storage = (uint8_t *)self->messageStorage_; + int64_t *typePtr = (int64_t *)&storage[field->description_->offset]; + *typePtr = value; + // proto2: any value counts as having been set; proto3, it + // has to be a non zero value. + BOOL hasValue = + (syntax == GPBFileSyntaxProto2) || (value != (int64_t)0); + GPBSetHasIvarField(self, field, hasValue); + GPBBecomeVisibleToAutocreator(self); +} + +//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(UInt64, uint64_t) +// This block of code is generated, do not edit it directly. + +uint64_t GPBGetUInt64IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field) { + if (GPBGetHasIvarField(self, field)) { + uint8_t *storage = (uint8_t *)self->messageStorage_; + uint64_t *typePtr = (uint64_t *)&storage[field->description_->offset]; + return *typePtr; + } else { + return field.defaultValue.valueUInt64; + } +} + +// Only exists for public api, no core code should use this. +void GPBSetUInt64IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + uint64_t value) { + if (self == nil || field == nil) return; + GPBFileSyntax syntax = [self descriptor].file.syntax; + GPBSetUInt64IvarWithFieldInternal(self, field, value, syntax); +} + +void GPBSetUInt64IvarWithFieldInternal(GPBMessage *self, + GPBFieldDescriptor *field, + uint64_t value, + GPBFileSyntax syntax) { + GPBOneofDescriptor *oneof = field->containingOneof_; + if (oneof) { + GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field)); + } + NSCAssert(self->messageStorage_ != NULL, @"How?"); +#if defined(__clang_analyzer__) + if (self->messageStorage_ == NULL) return; +#endif + uint8_t *storage = (uint8_t *)self->messageStorage_; + uint64_t *typePtr = (uint64_t *)&storage[field->description_->offset]; + *typePtr = value; + // proto2: any value counts as having been set; proto3, it + // has to be a non zero value. + BOOL hasValue = + (syntax == GPBFileSyntaxProto2) || (value != (uint64_t)0); + GPBSetHasIvarField(self, field, hasValue); + GPBBecomeVisibleToAutocreator(self); +} + +//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Float, float) +// This block of code is generated, do not edit it directly. + +float GPBGetFloatIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field) { + if (GPBGetHasIvarField(self, field)) { + uint8_t *storage = (uint8_t *)self->messageStorage_; + float *typePtr = (float *)&storage[field->description_->offset]; + return *typePtr; + } else { + return field.defaultValue.valueFloat; + } +} + +// Only exists for public api, no core code should use this. +void GPBSetFloatIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + float value) { + if (self == nil || field == nil) return; + GPBFileSyntax syntax = [self descriptor].file.syntax; + GPBSetFloatIvarWithFieldInternal(self, field, value, syntax); +} + +void GPBSetFloatIvarWithFieldInternal(GPBMessage *self, + GPBFieldDescriptor *field, + float value, + GPBFileSyntax syntax) { + GPBOneofDescriptor *oneof = field->containingOneof_; + if (oneof) { + GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field)); + } + NSCAssert(self->messageStorage_ != NULL, @"How?"); +#if defined(__clang_analyzer__) + if (self->messageStorage_ == NULL) return; +#endif + uint8_t *storage = (uint8_t *)self->messageStorage_; + float *typePtr = (float *)&storage[field->description_->offset]; + *typePtr = value; + // proto2: any value counts as having been set; proto3, it + // has to be a non zero value. + BOOL hasValue = + (syntax == GPBFileSyntaxProto2) || (value != (float)0); + GPBSetHasIvarField(self, field, hasValue); + GPBBecomeVisibleToAutocreator(self); +} + +//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Double, double) +// This block of code is generated, do not edit it directly. + +double GPBGetDoubleIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field) { + if (GPBGetHasIvarField(self, field)) { + uint8_t *storage = (uint8_t *)self->messageStorage_; + double *typePtr = (double *)&storage[field->description_->offset]; + return *typePtr; + } else { + return field.defaultValue.valueDouble; + } +} + +// Only exists for public api, no core code should use this. +void GPBSetDoubleIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + double value) { + if (self == nil || field == nil) return; + GPBFileSyntax syntax = [self descriptor].file.syntax; + GPBSetDoubleIvarWithFieldInternal(self, field, value, syntax); +} + +void GPBSetDoubleIvarWithFieldInternal(GPBMessage *self, + GPBFieldDescriptor *field, + double value, + GPBFileSyntax syntax) { + GPBOneofDescriptor *oneof = field->containingOneof_; + if (oneof) { + GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field)); + } + NSCAssert(self->messageStorage_ != NULL, @"How?"); +#if defined(__clang_analyzer__) + if (self->messageStorage_ == NULL) return; +#endif + uint8_t *storage = (uint8_t *)self->messageStorage_; + double *typePtr = (double *)&storage[field->description_->offset]; + *typePtr = value; + // proto2: any value counts as having been set; proto3, it + // has to be a non zero value. + BOOL hasValue = + (syntax == GPBFileSyntaxProto2) || (value != (double)0); + GPBSetHasIvarField(self, field, hasValue); + GPBBecomeVisibleToAutocreator(self); +} + +//%PDDM-EXPAND-END (7 expansions) + +// Aliases are function calls that are virtually the same. + +//%PDDM-EXPAND IVAR_ALIAS_DEFN(SInt32, Int32, int32_t, int32_t) +// This block of code is generated, do not edit it directly. + +// Only exists for public api, no core code should use this. +int32_t GPBGetSInt32IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field) { + return (int32_t)GPBGetInt32IvarWithField(self, field); +} + +// Only exists for public api, no core code should use this. +void GPBSetSInt32IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + int32_t value) { + GPBSetInt32IvarWithField(self, field, (int32_t)value); +} + +//%PDDM-EXPAND IVAR_ALIAS_DEFN(SFixed32, Int32, int32_t, int32_t) +// This block of code is generated, do not edit it directly. + +// Only exists for public api, no core code should use this. +int32_t GPBGetSFixed32IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field) { + return (int32_t)GPBGetInt32IvarWithField(self, field); +} + +// Only exists for public api, no core code should use this. +void GPBSetSFixed32IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + int32_t value) { + GPBSetInt32IvarWithField(self, field, (int32_t)value); +} + +//%PDDM-EXPAND IVAR_ALIAS_DEFN(Fixed32, UInt32, uint32_t, uint32_t) +// This block of code is generated, do not edit it directly. + +// Only exists for public api, no core code should use this. +uint32_t GPBGetFixed32IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field) { + return (uint32_t)GPBGetUInt32IvarWithField(self, field); +} + +// Only exists for public api, no core code should use this. +void GPBSetFixed32IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + uint32_t value) { + GPBSetUInt32IvarWithField(self, field, (uint32_t)value); +} + +//%PDDM-EXPAND IVAR_ALIAS_DEFN(SInt64, Int64, int64_t, int64_t) +// This block of code is generated, do not edit it directly. + +// Only exists for public api, no core code should use this. +int64_t GPBGetSInt64IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field) { + return (int64_t)GPBGetInt64IvarWithField(self, field); +} + +// Only exists for public api, no core code should use this. +void GPBSetSInt64IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + int64_t value) { + GPBSetInt64IvarWithField(self, field, (int64_t)value); +} + +//%PDDM-EXPAND IVAR_ALIAS_DEFN(SFixed64, Int64, int64_t, int64_t) +// This block of code is generated, do not edit it directly. + +// Only exists for public api, no core code should use this. +int64_t GPBGetSFixed64IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field) { + return (int64_t)GPBGetInt64IvarWithField(self, field); +} + +// Only exists for public api, no core code should use this. +void GPBSetSFixed64IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + int64_t value) { + GPBSetInt64IvarWithField(self, field, (int64_t)value); +} + +//%PDDM-EXPAND IVAR_ALIAS_DEFN(Fixed64, UInt64, uint64_t, uint64_t) +// This block of code is generated, do not edit it directly. + +// Only exists for public api, no core code should use this. +uint64_t GPBGetFixed64IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field) { + return (uint64_t)GPBGetUInt64IvarWithField(self, field); +} + +// Only exists for public api, no core code should use this. +void GPBSetFixed64IvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + uint64_t value) { + GPBSetUInt64IvarWithField(self, field, (uint64_t)value); +} + +//%PDDM-EXPAND IVAR_ALIAS_DEFN(String, Object, NSString*, id) +// This block of code is generated, do not edit it directly. + +// Only exists for public api, no core code should use this. +NSString* GPBGetStringIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field) { + return (NSString*)GPBGetObjectIvarWithField(self, field); +} + +// Only exists for public api, no core code should use this. +void GPBSetStringIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + NSString* value) { + GPBSetObjectIvarWithField(self, field, (id)value); +} + +//%PDDM-EXPAND IVAR_ALIAS_DEFN(Data, Object, NSData*, id) +// This block of code is generated, do not edit it directly. + +// Only exists for public api, no core code should use this. +NSData* GPBGetDataIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field) { + return (NSData*)GPBGetObjectIvarWithField(self, field); +} + +// Only exists for public api, no core code should use this. +void GPBSetDataIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + NSData* value) { + GPBSetObjectIvarWithField(self, field, (id)value); +} + +//%PDDM-EXPAND IVAR_ALIAS_DEFN(Message, Object, GPBMessage*, id) +// This block of code is generated, do not edit it directly. + +// Only exists for public api, no core code should use this. +GPBMessage* GPBGetMessageIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field) { + return (GPBMessage*)GPBGetObjectIvarWithField(self, field); +} + +// Only exists for public api, no core code should use this. +void GPBSetMessageIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + GPBMessage* value) { + GPBSetObjectIvarWithField(self, field, (id)value); +} + +//%PDDM-EXPAND IVAR_ALIAS_DEFN(Group, Object, GPBMessage*, id) +// This block of code is generated, do not edit it directly. + +// Only exists for public api, no core code should use this. +GPBMessage* GPBGetGroupIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field) { + return (GPBMessage*)GPBGetObjectIvarWithField(self, field); +} + +// Only exists for public api, no core code should use this. +void GPBSetGroupIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field, + GPBMessage* value) { + GPBSetObjectIvarWithField(self, field, (id)value); +} + +//%PDDM-EXPAND-END (10 expansions) + +#pragma mark - Misc Dynamic Runtime Utils + +void GPBApplyFunctionsToMessageFields(GPBApplyFunctions *functions, + GPBMessage *msg, void *context) { + GPBDescriptor *descriptor = [[msg class] descriptor]; + for (GPBFieldDescriptor *field in descriptor->fields_) { + BOOL wasGood; + if (GPBFieldIsMapOrArray(field)) { + wasGood = (*functions)[GPBApplyFunctionObject](field, context); + } else { + wasGood = GPBApplyFunctionsBasedOnField(field, functions, context); + } + if (!wasGood) { + break; + } + } +} + +BOOL GPBApplyFunctionsBasedOnField(GPBFieldDescriptor *field, + GPBApplyFunctions *functions, + void *context) { + static const GPBApplyFunctionOrder typeMap[GPBTypeCount] = { + GPBApplyFunctionBool, + GPBApplyFunctionUInt32, + GPBApplyFunctionInt32, + GPBApplyFunctionFloat, + GPBApplyFunctionUInt64, + GPBApplyFunctionInt64, + GPBApplyFunctionDouble, + GPBApplyFunctionInt32, + GPBApplyFunctionInt64, + GPBApplyFunctionInt32, + GPBApplyFunctionInt64, + GPBApplyFunctionUInt32, + GPBApplyFunctionUInt64, + GPBApplyFunctionObject, + GPBApplyFunctionObject, + GPBApplyFunctionObject, + GPBApplyFunctionObject, + GPBApplyFunctionInt32 + }; + return (*functions)[typeMap[GPBGetFieldType(field)]](field, context); +} + +void GPBApplyStrictFunctionsToMessageFields(GPBApplyStrictFunctions *functions, + GPBMessage *msg, void *context) { + GPBDescriptor *descriptor = [[msg class] descriptor]; + for (GPBFieldDescriptor *fieldDescriptor in descriptor->fields_) { + GPBApplyFunction function = (*functions)[GPBGetFieldType(fieldDescriptor)]; + BOOL wasGood = function(fieldDescriptor, context); + if (!wasGood) { + break; + } + } +} + +const char *GPBMessageEncodingForSelector(SEL selector, BOOL instanceSel) { + Protocol *protocol = + objc_getProtocol(GPBStringifySymbol(GPBMessageSignatureProtocol)); + struct objc_method_description description = + protocol_getMethodDescription(protocol, selector, NO, instanceSel); + return description.types; +} + +#pragma mark - Text Format Support + +static void AppendStringEscaped(NSString *toPrint, NSMutableString *destStr) { + [destStr appendString:@"\""]; + NSUInteger len = [toPrint length]; + for (NSUInteger i = 0; i < len; ++i) { + unichar aChar = [toPrint characterAtIndex:i]; + switch (aChar) { + case '\n': [destStr appendString:@"\\n"]; break; + case '\r': [destStr appendString:@"\\r"]; break; + case '\t': [destStr appendString:@"\\t"]; break; + case '\"': [destStr appendString:@"\\\""]; break; + case '\'': [destStr appendString:@"\\\'"]; break; + case '\\': [destStr appendString:@"\\\\"]; break; + default: + [destStr appendFormat:@"%C", aChar]; + break; + } + } + [destStr appendString:@"\""]; +} + +static void AppendBufferAsString(NSData *buffer, NSMutableString *destStr) { + const char *src = (const char *)[buffer bytes]; + size_t srcLen = [buffer length]; + [destStr appendString:@"\""]; + for (const char *srcEnd = src + srcLen; src < srcEnd; src++) { + switch (*src) { + case '\n': [destStr appendString:@"\\n"]; break; + case '\r': [destStr appendString:@"\\r"]; break; + case '\t': [destStr appendString:@"\\t"]; break; + case '\"': [destStr appendString:@"\\\""]; break; + case '\'': [destStr appendString:@"\\\'"]; break; + case '\\': [destStr appendString:@"\\\\"]; break; + default: + if (isprint(*src)) { + [destStr appendFormat:@"%c", *src]; + } else { + // NOTE: doing hex means you have to worry about the letter after + // the hex being another hex char and forcing that to be escaped, so + // use octal to keep it simple. + [destStr appendFormat:@"\\%03o", (uint8_t)(*src)]; + } + break; + } + } + [destStr appendString:@"\""]; +} + +static void AppendTextFormatForMapMessageField( + id map, GPBFieldDescriptor *field, NSMutableString *toStr, + NSString *lineIndent, NSString *fieldName, NSString *lineEnding) { + GPBType keyType = field.mapKeyType; + GPBType valueType = GPBGetFieldType(field); + BOOL isMessageValue = GPBTypeIsMessage(valueType); + + NSString *msgStartFirst = + [NSString stringWithFormat:@"%@%@ {%@\n", lineIndent, fieldName, lineEnding]; + NSString *msgStart = + [NSString stringWithFormat:@"%@%@ {\n", lineIndent, fieldName]; + NSString *msgEnd = [NSString stringWithFormat:@"%@}\n", lineIndent]; + + NSString *keyLine = [NSString stringWithFormat:@"%@ key: ", lineIndent]; + NSString *valueLine = [NSString stringWithFormat:@"%@ value%s ", lineIndent, + (isMessageValue ? "" : ":")]; + + __block BOOL isFirst = YES; + + if ((keyType == GPBTypeString) && GPBTypeIsObject(valueType)) { + // map is an NSDictionary. + NSDictionary *dict = map; + [dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) { + #pragma unused(stop) + [toStr appendString:(isFirst ? msgStartFirst : msgStart)]; + isFirst = NO; + + [toStr appendString:keyLine]; + AppendStringEscaped(key, toStr); + [toStr appendString:@"\n"]; + + [toStr appendString:valueLine]; + switch (valueType) { + case GPBTypeString: + AppendStringEscaped(value, toStr); + break; + + case GPBTypeData: + AppendBufferAsString(value, toStr); + break; + + case GPBTypeMessage: + [toStr appendString:@"{\n"]; + NSString *subIndent = [lineIndent stringByAppendingString:@" "]; + AppendTextFormatForMessage(value, toStr, subIndent); + [toStr appendFormat:@"%@ }", lineIndent]; + break; + + default: + NSCAssert(NO, @"Can't happen"); + break; + } + [toStr appendString:@"\n"]; + + [toStr appendString:msgEnd]; + }]; + } else { + // map is one of the GPB*Dictionary classes, type doesn't matter. + GPBInt32Int32Dictionary *dict = map; + [dict enumerateForTextFormat:^(id keyObj, id valueObj) { + [toStr appendString:(isFirst ? msgStartFirst : msgStart)]; + isFirst = NO; + + // Key always is a NSString. + if (keyType == GPBTypeString) { + [toStr appendString:keyLine]; + AppendStringEscaped(keyObj, toStr); + [toStr appendString:@"\n"]; + } else { + [toStr appendFormat:@"%@%@\n", keyLine, keyObj]; + } + + [toStr appendString:valueLine]; + switch (valueType) { + case GPBTypeString: + AppendStringEscaped(valueObj, toStr); + break; + + case GPBTypeData: + AppendBufferAsString(valueObj, toStr); + break; + + case GPBTypeMessage: + [toStr appendString:@"{\n"]; + NSString *subIndent = [lineIndent stringByAppendingString:@" "]; + AppendTextFormatForMessage(valueObj, toStr, subIndent); + [toStr appendFormat:@"%@ }", lineIndent]; + break; + + case GPBTypeEnum: { + int32_t enumValue = [valueObj intValue]; + NSString *valueStr = nil; + GPBEnumDescriptor *descriptor = field.enumDescriptor; + if (descriptor) { + valueStr = [descriptor textFormatNameForValue:enumValue]; + } + if (valueStr) { + [toStr appendString:valueStr]; + } else { + [toStr appendFormat:@"%d", enumValue]; + } + break; + } + + default: + NSCAssert(valueType != GPBTypeGroup, @"Can't happen"); + // Everything else is a NSString. + [toStr appendString:valueObj]; + break; + } + [toStr appendString:@"\n"]; + + [toStr appendString:msgEnd]; + }]; + } +} + +static void AppendTextFormatForMessageField(GPBMessage *message, + GPBFieldDescriptor *field, + NSMutableString *toStr, + NSString *lineIndent) { + id array; + NSUInteger arrayCount; + GPBFieldType fieldType = field.fieldType; + switch (fieldType) { + case GPBFieldTypeSingle: + array = nil; + arrayCount = (GPBGetHasIvarField(message, field) ? 1 : 0); + break; + + case GPBFieldTypeRepeated: + array = GPBGetObjectIvarWithFieldNoAutocreate(message, field); + arrayCount = [(NSArray *)array count]; + break; + + case GPBFieldTypeMap: { + // Could be a GPB*Dictionary or NSMutableDictionary, type doesn't matter, + // just want count. + array = GPBGetObjectIvarWithFieldNoAutocreate(message, field); + arrayCount = [(NSArray *)array count]; + break; + } + } + + if (arrayCount == 0) { + // Nothing to print, out of here. + return; + } + + NSString *lineEnding = @""; + + // If the name can't be reversed or support for extra info was turned off, + // this can return nil. + NSString *fieldName = [field textFormatName]; + if ([fieldName length] == 0) { + fieldName = [NSString stringWithFormat:@"%u", GPBFieldNumber(field)]; + // If there is only one entry, put the objc name as a comment, other wise + // add it before the the repeated values. + if (arrayCount > 1) { + [toStr appendFormat:@"%@# %@\n", lineIndent, field.name]; + } else { + lineEnding = [NSString stringWithFormat:@" # %@", field.name]; + } + } + + if (fieldType == GPBFieldTypeMap) { + AppendTextFormatForMapMessageField(array, field, toStr, lineIndent, + fieldName, lineEnding); + return; + } + + const BOOL isRepeated = (array != nil); + + GPBType fieldDataType = GPBGetFieldType(field); + BOOL isMessageField = GPBTypeIsMessage(fieldDataType); + for (NSUInteger j = 0; j < arrayCount; ++j) { + // Start the line. + [toStr appendFormat:@"%@%@%s ", lineIndent, fieldName, + (isMessageField ? "" : ":")]; + + // The value. + switch (fieldDataType) { +#define FIELD_CASE(GPBTYPE, CTYPE, ARRAY_TYPE, ...) \ + case GPBType##GPBTYPE: { \ + CTYPE v = (isRepeated ? [(GPB##ARRAY_TYPE##Array *)array valueAtIndex:j] \ + : GPBGet##GPBTYPE##IvarWithField(message, field)); \ + [toStr appendFormat:__VA_ARGS__, v]; \ + break; \ + } + + FIELD_CASE(Int32, int32_t, Int32, @"%d") + FIELD_CASE(SInt32, int32_t, Int32, @"%d") + FIELD_CASE(SFixed32, int32_t, Int32, @"%d") + FIELD_CASE(UInt32, uint32_t, UInt32, @"%u") + FIELD_CASE(Fixed32, uint32_t, UInt32, @"%u") + FIELD_CASE(Int64, int64_t, Int64, @"%lld") + FIELD_CASE(SInt64, int64_t, Int64, @"%lld") + FIELD_CASE(SFixed64, int64_t, Int64, @"%lld") + FIELD_CASE(UInt64, uint64_t, UInt64, @"%llu") + FIELD_CASE(Fixed64, uint64_t, UInt64, @"%llu") + FIELD_CASE(Float, float, Float, @"%.*g", FLT_DIG) + FIELD_CASE(Double, double, Double, @"%.*lg", DBL_DIG) + +#undef FIELD_CASE + + case GPBTypeEnum: { + int32_t v = (isRepeated ? [(GPBEnumArray *)array rawValueAtIndex:j] + : GPBGetInt32IvarWithField(message, field)); + NSString *valueStr = nil; + GPBEnumDescriptor *descriptor = field.enumDescriptor; + if (descriptor) { + valueStr = [descriptor textFormatNameForValue:v]; + } + if (valueStr) { + [toStr appendString:valueStr]; + } else { + [toStr appendFormat:@"%d", v]; + } + break; + } + + case GPBTypeBool: { + BOOL v = (isRepeated ? [(GPBBoolArray *)array valueAtIndex:j] + : GPBGetBoolIvarWithField(message, field)); + [toStr appendString:(v ? @"true" : @"false")]; + break; + } + + case GPBTypeString: { + NSString *v = (isRepeated ? [(NSArray *)array objectAtIndex:j] + : GPBGetStringIvarWithField(message, field)); + AppendStringEscaped(v, toStr); + break; + } + + case GPBTypeData: { + NSData *v = (isRepeated ? [(NSArray *)array objectAtIndex:j] + : GPBGetDataIvarWithField(message, field)); + AppendBufferAsString(v, toStr); + break; + } + + case GPBTypeGroup: + case GPBTypeMessage: { + GPBMessage *v = + (isRepeated ? [(NSArray *)array objectAtIndex:j] + : GPBGetObjectIvarWithField(message, field)); + [toStr appendFormat:@"{%@\n", lineEnding]; + NSString *subIndent = [lineIndent stringByAppendingString:@" "]; + AppendTextFormatForMessage(v, toStr, subIndent); + [toStr appendFormat:@"%@}", lineIndent]; + lineEnding = @""; + break; + } + + } // switch(fieldDataType) + + // End the line. + [toStr appendFormat:@"%@\n", lineEnding]; + + } // for(arrayCount) +} + +static void AppendTextFormatForMessageExtensionRange(GPBMessage *message, + NSArray *activeExtensions, + GPBExtensionRange range, + NSMutableString *toStr, + NSString *lineIndent) { + uint32_t start = range.start; + uint32_t end = range.end; + for (GPBExtensionField *extension in activeExtensions) { + uint32_t fieldNumber = extension.fieldNumber; + if (fieldNumber < start) { + // Not there yet. + continue; + } + if (fieldNumber > end) { + // Done. + break; + } + + id rawExtValue = [message getExtension:extension]; + GPBExtensionDescriptor *extDescriptor = [extension descriptor]; + BOOL isRepeated = extDescriptor.isRepeated; + + NSUInteger numValues = 1; + NSString *lineEnding = @""; + if (isRepeated) { + numValues = [(NSArray *)rawExtValue count]; + } + + NSString *singletonName = extension.descriptor.singletonName; + if (numValues == 1) { + lineEnding = [NSString stringWithFormat:@" # [%@]", singletonName]; + } else { + [toStr appendFormat:@"%@# [%@]\n", lineIndent, singletonName]; + } + + GPBType extType = extDescriptor.type; + for (NSUInteger j = 0; j < numValues; ++j) { + id curValue = (isRepeated ? [rawExtValue objectAtIndex:j] : rawExtValue); + + // Start the line. + [toStr appendFormat:@"%@%u%s ", lineIndent, fieldNumber, + (GPBTypeIsMessage(extType) ? "" : ":")]; + + // The value. + switch (extType) { +#define FIELD_CASE(GPBTYPE, CTYPE, NUMSELECTOR, ...) \ + case GPBType##GPBTYPE: { \ + CTYPE v = [(NSNumber *)curValue NUMSELECTOR]; \ + [toStr appendFormat:__VA_ARGS__, v]; \ + break; \ + } + + FIELD_CASE(Int32, int32_t, intValue, @"%d") + FIELD_CASE(SInt32, int32_t, intValue, @"%d") + FIELD_CASE(SFixed32, int32_t, unsignedIntValue, @"%d") + FIELD_CASE(UInt32, uint32_t, unsignedIntValue, @"%u") + FIELD_CASE(Fixed32, uint32_t, unsignedIntValue, @"%u") + FIELD_CASE(Int64, int64_t, longLongValue, @"%lld") + FIELD_CASE(SInt64, int64_t, longLongValue, @"%lld") + FIELD_CASE(SFixed64, int64_t, longLongValue, @"%lld") + FIELD_CASE(UInt64, uint64_t, unsignedLongLongValue, @"%llu") + FIELD_CASE(Fixed64, uint64_t, unsignedLongLongValue, @"%llu") + FIELD_CASE(Float, float, floatValue, @"%.*g", FLT_DIG) + FIELD_CASE(Double, double, doubleValue, @"%.*lg", DBL_DIG) + // TODO: Add a comment with the enum name from enum descriptors + // (might not be real value, so leave it as a comment, ObjC compiler + // name mangles differently). Doesn't look like we actually generate + // an enum descriptor reference like we do for normal fields, so this + // will take a compiler change. + FIELD_CASE(Enum, int32_t, intValue, @"%d") + +#undef FIELD_CASE + + case GPBTypeBool: + [toStr appendString:([(NSNumber *)curValue boolValue] ? @"true" + : @"false")]; + break; + + case GPBTypeString: + AppendStringEscaped(curValue, toStr); + break; + + case GPBTypeData: + AppendBufferAsString((NSData *)curValue, toStr); + break; + + case GPBTypeGroup: + case GPBTypeMessage: { + [toStr appendFormat:@"{%@\n", lineEnding]; + NSString *subIndent = [lineIndent stringByAppendingString:@" "]; + AppendTextFormatForMessage(curValue, toStr, subIndent); + [toStr appendFormat:@"%@}", lineIndent]; + lineEnding = @""; + break; + } + + } // switch(extType) + + } // for(numValues) + + // End the line. + [toStr appendFormat:@"%@\n", lineEnding]; + + } // for..in(activeExtensions) +} + +static void AppendTextFormatForMessage(GPBMessage *message, + NSMutableString *toStr, + NSString *lineIndent) { + GPBDescriptor *descriptor = [message descriptor]; + NSArray *fieldsArray = descriptor->fields_; + NSUInteger fieldCount = fieldsArray.count; + const GPBExtensionRange *extensionRanges = descriptor.extensionRanges; + NSUInteger extensionRangesCount = descriptor.extensionRangesCount; + NSArray *activeExtensions = [message sortedExtensionsInUse]; + for (NSUInteger i = 0, j = 0; i < fieldCount || j < extensionRangesCount;) { + if (i == fieldCount) { + AppendTextFormatForMessageExtensionRange( + message, activeExtensions, extensionRanges[j++], toStr, lineIndent); + } else if (j == extensionRangesCount || + GPBFieldNumber(fieldsArray[i]) < extensionRanges[j].start) { + AppendTextFormatForMessageField(message, fieldsArray[i++], toStr, + lineIndent); + } else { + AppendTextFormatForMessageExtensionRange( + message, activeExtensions, extensionRanges[j++], toStr, lineIndent); + } + } + + NSString *unknownFieldsStr = + GPBTextFormatForUnknownFieldSet(message.unknownFields, lineIndent); + if ([unknownFieldsStr length] > 0) { + [toStr appendFormat:@"%@# --- Unknown fields ---\n", lineIndent]; + [toStr appendString:unknownFieldsStr]; + } +} + +NSString *GPBTextFormatForMessage(GPBMessage *message, NSString *lineIndent) { + if (message == nil) return nil; + if (lineIndent == nil) lineIndent = @""; + + NSMutableString *buildString = [NSMutableString string]; + AppendTextFormatForMessage(message, buildString, lineIndent); + return buildString; +} + +NSString *GPBTextFormatForUnknownFieldSet(GPBUnknownFieldSet *unknownSet, + NSString *lineIndent) { + if (unknownSet == nil) return nil; + if (lineIndent == nil) lineIndent = @""; + + NSMutableString *result = [NSMutableString string]; + for (GPBField *field in [unknownSet sortedFields]) { + int32_t fieldNumber = [field number]; + +#define PRINT_LOOP(PROPNAME, CTYPE, FORMAT) \ + [field.PROPNAME \ + enumerateValuesWithBlock:^(CTYPE value, NSUInteger idx, BOOL * stop) { \ + _Pragma("unused(idx, stop)"); \ + [result \ + appendFormat:@"%@%d: " #FORMAT "\n", lineIndent, fieldNumber, value]; \ + }]; + + PRINT_LOOP(varintList, uint64_t, %llu); + PRINT_LOOP(fixed32List, uint32_t, 0x%X); + PRINT_LOOP(fixed64List, uint64_t, 0x%llX); + +#undef PRINT_LOOP + + // NOTE: C++ version of TextFormat tries to parse this as a message + // and print that if it succeeds. + for (NSData *data in field.lengthDelimitedList) { + [result appendFormat:@"%@%d: ", lineIndent, fieldNumber]; + AppendBufferAsString(data, result); + [result appendString:@"\n"]; + } + + for (GPBUnknownFieldSet *subUnknownSet in field.groupList) { + [result appendFormat:@"%@%d: {\n", lineIndent, fieldNumber]; + NSString *subIndent = [lineIndent stringByAppendingString:@" "]; + NSString *subUnknwonSetStr = + GPBTextFormatForUnknownFieldSet(subUnknownSet, subIndent); + [result appendString:subUnknwonSetStr]; + [result appendFormat:@"%@}\n", lineIndent]; + } + } + return result; +} + +// Helpers to decode a varint. Not using GPBCodedInputStream version because +// that needs a state object, and we don't want to create an input stream out +// of the data. +static inline int8_t ReadRawByteFromData(const uint8_t **data) { + int8_t result = *((int8_t *)(*data)); + ++(*data); + return result; +} + +static inline int32_t ReadRawVarint32FromData(const uint8_t **data) { + int8_t tmp = ReadRawByteFromData(data); + if (tmp >= 0) { + return tmp; + } + int32_t result = tmp & 0x7f; + if ((tmp = ReadRawByteFromData(data)) >= 0) { + result |= tmp << 7; + } else { + result |= (tmp & 0x7f) << 7; + if ((tmp = ReadRawByteFromData(data)) >= 0) { + result |= tmp << 14; + } else { + result |= (tmp & 0x7f) << 14; + if ((tmp = ReadRawByteFromData(data)) >= 0) { + result |= tmp << 21; + } else { + result |= (tmp & 0x7f) << 21; + result |= (tmp = ReadRawByteFromData(data)) << 28; + if (tmp < 0) { + // Discard upper 32 bits. + for (int i = 0; i < 5; i++) { + if (ReadRawByteFromData(data) >= 0) { + return result; + } + } + [NSException raise:NSParseErrorException + format:@"Unable to read varint32"]; + } + } + } + } + return result; +} + +NSString *GPBDecodeTextFormatName(const uint8_t *decodeData, int32_t key, + NSString *inputStr) { + // decodData form: + // varint32: num entries + // for each entry: + // varint32: key + // bytes*: decode data + // + // decode data one of two forms: + // 1: a \0 followed by the string followed by an \0 + // 2: bytecodes to transform an input into the right thing, ending with \0 + // + // the bytes codes are of the form: + // 0xabbccccc + // 0x0 (all zeros), end. + // a - if set, add an underscore + // bb - 00 ccccc bytes as is + // bb - 10 ccccc upper first, as is on rest, ccccc byte total + // bb - 01 ccccc lower first, as is on rest, ccccc byte total + // bb - 11 ccccc all upper, ccccc byte total + + if (!decodeData || !inputStr) { + return nil; + } + + // Find key + const uint8_t *scan = decodeData; + int32_t numEntries = ReadRawVarint32FromData(&scan); + BOOL foundKey = NO; + while (!foundKey && (numEntries > 0)) { + --numEntries; + int32_t dataKey = ReadRawVarint32FromData(&scan); + if (dataKey == key) { + foundKey = YES; + } else { + // If it is a inlined string, it will start with \0; if it is bytecode it + // will start with a code. So advance one (skipping the inline string + // marker), and then loop until reaching the end marker (\0). + ++scan; + while (*scan != 0) ++scan; + // Now move past the end marker. + ++scan; + } + } + + if (!foundKey) { + return nil; + } + + // Decode + + if (*scan == 0) { + // Inline string. Move over the marker, and NSString can take it as + // UTF8. + ++scan; + NSString *result = [NSString stringWithUTF8String:(const char *)scan]; + return result; + } + + NSMutableString *result = + [NSMutableString stringWithCapacity:[inputStr length]]; + + const uint8_t kAddUnderscore = 0b10000000; + const uint8_t kOpMask = 0b01100000; + // const uint8_t kOpAsIs = 0b00000000; + const uint8_t kOpFirstUpper = 0b01000000; + const uint8_t kOpFirstLower = 0b00100000; + const uint8_t kOpAllUpper = 0b01100000; + const uint8_t kSegmentLenMask = 0b00011111; + + NSInteger i = 0; + for (; *scan != 0; ++scan) { + if (*scan & kAddUnderscore) { + [result appendString:@"_"]; + } + int segmentLen = *scan & kSegmentLenMask; + uint8_t decodeOp = *scan & kOpMask; + + // Do op specific handling of the first character. + if (decodeOp == kOpFirstUpper) { + unichar c = [inputStr characterAtIndex:i]; + [result appendFormat:@"%c", toupper((char)c)]; + ++i; + --segmentLen; + } else if (decodeOp == kOpFirstLower) { + unichar c = [inputStr characterAtIndex:i]; + [result appendFormat:@"%c", tolower((char)c)]; + ++i; + --segmentLen; + } + // else op == kOpAsIs || op == kOpAllUpper + + // Now pull over the rest of the length for this segment. + for (int x = 0; x < segmentLen; ++x) { + unichar c = [inputStr characterAtIndex:(i + x)]; + if (decodeOp == kOpAllUpper) { + [result appendFormat:@"%c", toupper((char)c)]; + } else { + [result appendFormat:@"%C", c]; + } + } + i += segmentLen; + } + + return result; +} + +#pragma mark - GPBMessageSignatureProtocol + +// A series of selectors that are used solely to get @encoding values +// for them by the dynamic protobuf runtime code. An object using the protocol +// needs to be declared for the protocol to be valid at runtime. +@interface GPBMessageSignatureProtocol : NSObject<GPBMessageSignatureProtocol> +@end +@implementation GPBMessageSignatureProtocol +@end diff --git a/objectivec/GPBUtilities_PackagePrivate.h b/objectivec/GPBUtilities_PackagePrivate.h new file mode 100644 index 00000000..1481d071 --- /dev/null +++ b/objectivec/GPBUtilities_PackagePrivate.h @@ -0,0 +1,426 @@ +// 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. + +#import <Foundation/Foundation.h> + +#import "GPBUtilities.h" + +#import "GPBDescriptor_PackagePrivate.h" + +// Macros for stringifying library symbols. These are used in the generated +// PB descriptor classes wherever a library symbol name is represented as a +// string. See README.google for more information. +#define GPBStringify(S) #S +#define GPBStringifySymbol(S) GPBStringify(S) + +#define GPBNSStringify(S) @#S +#define GPBNSStringifySymbol(S) GPBNSStringify(S) + +// Constant to internally mark when there is no has bit. +#define GPBNoHasBit INT32_MAX + +CF_EXTERN_C_BEGIN + +// Conversion functions for de/serializing floating point types. + +GPB_INLINE int64_t GPBConvertDoubleToInt64(double v) { + union { double f; int64_t i; } u; + u.f = v; + return u.i; +} + +GPB_INLINE int32_t GPBConvertFloatToInt32(float v) { + union { float f; int32_t i; } u; + u.f = v; + return u.i; +} + +GPB_INLINE double GPBConvertInt64ToDouble(int64_t v) { + union { double f; int64_t i; } u; + u.i = v; + return u.f; +} + +GPB_INLINE float GPBConvertInt32ToFloat(int32_t v) { + union { float f; int32_t i; } u; + u.i = v; + return u.f; +} + +GPB_INLINE int32_t GPBLogicalRightShift32(int32_t value, int32_t spaces) { + return (int32_t)((uint32_t)(value) >> spaces); +} + +GPB_INLINE int64_t GPBLogicalRightShift64(int64_t value, int32_t spaces) { + return (int64_t)((uint64_t)(value) >> spaces); +} + +// Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers +// into values that can be efficiently encoded with varint. (Otherwise, +// negative values must be sign-extended to 64 bits to be varint encoded, +// thus always taking 10 bytes on the wire.) +GPB_INLINE int32_t GPBDecodeZigZag32(uint32_t n) { + return GPBLogicalRightShift32(n, 1) ^ -(n & 1); +} + +// Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers +// into values that can be efficiently encoded with varint. (Otherwise, +// negative values must be sign-extended to 64 bits to be varint encoded, +// thus always taking 10 bytes on the wire.) +GPB_INLINE int64_t GPBDecodeZigZag64(uint64_t n) { + return GPBLogicalRightShift64(n, 1) ^ -(n & 1); +} + +// Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers +// into values that can be efficiently encoded with varint. (Otherwise, +// negative values must be sign-extended to 64 bits to be varint encoded, +// thus always taking 10 bytes on the wire.) +GPB_INLINE uint32_t GPBEncodeZigZag32(int32_t n) { + // Note: the right-shift must be arithmetic + return (n << 1) ^ (n >> 31); +} + +// Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers +// into values that can be efficiently encoded with varint. (Otherwise, +// negative values must be sign-extended to 64 bits to be varint encoded, +// thus always taking 10 bytes on the wire.) +GPB_INLINE uint64_t GPBEncodeZigZag64(int64_t n) { + // Note: the right-shift must be arithmetic + return (n << 1) ^ (n >> 63); +} + +GPB_INLINE BOOL GPBTypeIsObject(GPBType type) { + switch (type) { + case GPBTypeData: + case GPBTypeString: + case GPBTypeMessage: + case GPBTypeGroup: + return YES; + default: + return NO; + } +} + +GPB_INLINE BOOL GPBTypeIsMessage(GPBType type) { + switch (type) { + case GPBTypeMessage: + case GPBTypeGroup: + return YES; + default: + return NO; + } +} + +GPB_INLINE BOOL GPBTypeIsEnum(GPBType type) { return type == GPBTypeEnum; } + +GPB_INLINE BOOL GPBFieldTypeIsMessage(GPBFieldDescriptor *field) { + return GPBTypeIsMessage(field->description_->type); +} + +GPB_INLINE BOOL GPBFieldTypeIsObject(GPBFieldDescriptor *field) { + return GPBTypeIsObject(field->description_->type); +} + +GPB_INLINE BOOL GPBExtensionIsMessage(GPBExtensionDescriptor *ext) { + return GPBTypeIsMessage(ext->description_->type); +} + +// The field is an array/map or it has an object value. +GPB_INLINE BOOL GPBFieldStoresObject(GPBFieldDescriptor *field) { + GPBMessageFieldDescription *desc = field->description_; + if ((desc->flags & (GPBFieldRepeated | GPBFieldMapKeyMask)) != 0) { + return YES; + } + return GPBTypeIsObject(desc->type); +} + +BOOL GPBGetHasIvar(GPBMessage *self, int32_t index, uint32_t fieldNumber); +void GPBSetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber, + BOOL value); +uint32_t GPBGetHasOneof(GPBMessage *self, int32_t index); + +GPB_INLINE BOOL +GPBGetHasIvarField(GPBMessage *self, GPBFieldDescriptor *field) { + GPBMessageFieldDescription *fieldDesc = field->description_; + return GPBGetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number); +} +GPB_INLINE void GPBSetHasIvarField(GPBMessage *self, GPBFieldDescriptor *field, + BOOL value) { + GPBMessageFieldDescription *fieldDesc = field->description_; + GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, value); +} + +void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof, + uint32_t fieldNumberNotToClear); + +//%PDDM-DEFINE GPB_IVAR_SET_DECL(NAME, TYPE) +//%void GPBSet##NAME##IvarWithFieldInternal(GPBMessage *self, +//% NAME$S GPBFieldDescriptor *field, +//% NAME$S TYPE value, +//% NAME$S GPBFileSyntax syntax); +//%PDDM-EXPAND GPB_IVAR_SET_DECL(Bool, BOOL) +// This block of code is generated, do not edit it directly. + +void GPBSetBoolIvarWithFieldInternal(GPBMessage *self, + GPBFieldDescriptor *field, + BOOL value, + GPBFileSyntax syntax); +//%PDDM-EXPAND GPB_IVAR_SET_DECL(Int32, int32_t) +// This block of code is generated, do not edit it directly. + +void GPBSetInt32IvarWithFieldInternal(GPBMessage *self, + GPBFieldDescriptor *field, + int32_t value, + GPBFileSyntax syntax); +//%PDDM-EXPAND GPB_IVAR_SET_DECL(UInt32, uint32_t) +// This block of code is generated, do not edit it directly. + +void GPBSetUInt32IvarWithFieldInternal(GPBMessage *self, + GPBFieldDescriptor *field, + uint32_t value, + GPBFileSyntax syntax); +//%PDDM-EXPAND GPB_IVAR_SET_DECL(Int64, int64_t) +// This block of code is generated, do not edit it directly. + +void GPBSetInt64IvarWithFieldInternal(GPBMessage *self, + GPBFieldDescriptor *field, + int64_t value, + GPBFileSyntax syntax); +//%PDDM-EXPAND GPB_IVAR_SET_DECL(UInt64, uint64_t) +// This block of code is generated, do not edit it directly. + +void GPBSetUInt64IvarWithFieldInternal(GPBMessage *self, + GPBFieldDescriptor *field, + uint64_t value, + GPBFileSyntax syntax); +//%PDDM-EXPAND GPB_IVAR_SET_DECL(Float, float) +// This block of code is generated, do not edit it directly. + +void GPBSetFloatIvarWithFieldInternal(GPBMessage *self, + GPBFieldDescriptor *field, + float value, + GPBFileSyntax syntax); +//%PDDM-EXPAND GPB_IVAR_SET_DECL(Double, double) +// This block of code is generated, do not edit it directly. + +void GPBSetDoubleIvarWithFieldInternal(GPBMessage *self, + GPBFieldDescriptor *field, + double value, + GPBFileSyntax syntax); +//%PDDM-EXPAND GPB_IVAR_SET_DECL(Enum, int32_t) +// This block of code is generated, do not edit it directly. + +void GPBSetEnumIvarWithFieldInternal(GPBMessage *self, + GPBFieldDescriptor *field, + int32_t value, + GPBFileSyntax syntax); +//%PDDM-EXPAND-END (8 expansions) + +int32_t GPBGetEnumIvarWithFieldInternal(GPBMessage *self, + GPBFieldDescriptor *field, + GPBFileSyntax syntax); + +id GPBGetObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field); + +void GPBSetObjectIvarWithFieldInternal(GPBMessage *self, + GPBFieldDescriptor *field, id value, + GPBFileSyntax syntax); +void GPBSetRetainedObjectIvarWithFieldInternal(GPBMessage *self, + GPBFieldDescriptor *field, + id __attribute__((ns_consumed)) + value, + GPBFileSyntax syntax); + +// GPBGetObjectIvarWithField will automatically create the field (message) if +// it doesn't exist. GPBGetObjectIvarWithFieldNoAutocreate will return nil. +id GPBGetObjectIvarWithFieldNoAutocreate(GPBMessage *self, + GPBFieldDescriptor *field); + +void GPBSetAutocreatedRetainedObjectIvarWithField( + GPBMessage *self, GPBFieldDescriptor *field, + id __attribute__((ns_consumed)) value); + +// Clears and releases the autocreated message ivar, if it's autocreated. If +// it's not set as autocreated, this method does nothing. +void GPBClearAutocreatedMessageIvarWithField(GPBMessage *self, + GPBFieldDescriptor *field); + +// Utilities for applying various functions based on Objective C types. + +// A basic functor that is passed a field and a context. Returns YES +// if the calling function should continue processing, and NO if the calling +// function should stop processing. +typedef BOOL (*GPBApplyFunction)(GPBFieldDescriptor *field, void *context); + +// Functions called for various types. See ApplyFunctionsToMessageFields. +typedef enum { + GPBApplyFunctionObject, + GPBApplyFunctionBool, + GPBApplyFunctionInt32, + GPBApplyFunctionUInt32, + GPBApplyFunctionInt64, + GPBApplyFunctionUInt64, + GPBApplyFunctionFloat, + GPBApplyFunctionDouble, +} GPBApplyFunctionOrder; + +enum { + // A count of the number of types in GPBApplyFunctionOrder. Separated out + // from the GPBApplyFunctionOrder enum to avoid warnings regarding not + // handling GPBApplyFunctionCount in switch statements. + GPBApplyFunctionCount = GPBApplyFunctionDouble + 1 +}; + +typedef GPBApplyFunction GPBApplyFunctions[GPBApplyFunctionCount]; + +// Functions called for various types. +// See ApplyStrictFunctionsToMessageFields. +// They are in the same order as the GPBTypes enum. +typedef GPBApplyFunction GPBApplyStrictFunctions[GPBTypeCount]; + +// A macro for easily initializing a GPBApplyFunctions struct +// GPBApplyFunctions foo = GPBAPPLY_FUNCTIONS_INIT(Foo); +#define GPBAPPLY_FUNCTIONS_INIT(PREFIX) \ + { \ + PREFIX##Object, \ + PREFIX##Bool, \ + PREFIX##Int32, \ + PREFIX##UInt32, \ + PREFIX##Int64, \ + PREFIX##UInt64, \ + PREFIX##Float, \ + PREFIX##Double, \ + } + +// A macro for easily initializing a GPBApplyStrictFunctions struct +// GPBApplyStrictFunctions foo = GPBAPPLY_STRICT_FUNCTIONS_INIT(Foo); +// These need to stay in the same order as +// the GPBType enum. +#define GPBAPPLY_STRICT_FUNCTIONS_INIT(PREFIX) \ + { \ + PREFIX##Bool, \ + PREFIX##Fixed32, \ + PREFIX##SFixed32, \ + PREFIX##Float, \ + PREFIX##Fixed64, \ + PREFIX##SFixed64, \ + PREFIX##Double, \ + PREFIX##Int32, \ + PREFIX##Int64, \ + PREFIX##SInt32, \ + PREFIX##SInt64, \ + PREFIX##UInt32, \ + PREFIX##UInt64, \ + PREFIX##Data, \ + PREFIX##String, \ + PREFIX##Message, \ + PREFIX##Group, \ + PREFIX##Enum, \ +} + +// Iterates over the fields of a proto |msg| and applies the functions in +// |functions| to them with |context|. If one of the functions in |functions| +// returns NO, it will return immediately and not process the rest of the +// ivars. The types in the fields are mapped so: +// Int32, Enum, SInt32 and SFixed32 will be mapped to the int32Function, +// UInt32 and Fixed32 will be mapped to the uint32Function, +// Bytes, String, Message and Group will be mapped to the objectFunction, +// etc.. +// If you require more specific mappings look at +// GPBApplyStrictFunctionsToMessageFields. +void GPBApplyFunctionsToMessageFields(GPBApplyFunctions *functions, + GPBMessage *msg, void *context); + +// Iterates over the fields of a proto |msg| and applies the functions in +// |functions| to them with |context|. If one of the functions in |functions| +// returns NO, it will return immediately and not process the rest of the +// ivars. The types in the fields are mapped directly: +// Int32 -> functions[GPBTypeInt32], +// SFixed32 -> functions[GPBTypeSFixed32], +// etc... +// If you can use looser mappings look at GPBApplyFunctionsToMessageFields. +void GPBApplyStrictFunctionsToMessageFields(GPBApplyStrictFunctions *functions, + GPBMessage *msg, void *context); + +// Applies the appropriate function in |functions| based on |field|. +// Returns the value from function(name, context). +// Throws an exception if the type is unrecognized. +BOOL GPBApplyFunctionsBasedOnField(GPBFieldDescriptor *field, + GPBApplyFunctions *functions, void *context); + +// Returns an Objective C encoding for |selector|. |instanceSel| should be +// YES if it's an instance selector (as opposed to a class selector). +// |selector| must be a selector from MessageSignatureProtocol. +const char *GPBMessageEncodingForSelector(SEL selector, BOOL instanceSel); + +// Helper for text format name encoding. +// decodeData is the data describing the sepecial decodes. +// key and inputString are the input that needs decoding. +NSString *GPBDecodeTextFormatName(const uint8_t *decodeData, int32_t key, + NSString *inputString); + +// A series of selectors that are used solely to get @encoding values +// for them by the dynamic protobuf runtime code. See +// GPBMessageEncodingForSelector for details. +@protocol GPBMessageSignatureProtocol +@optional + +#define GPB_MESSAGE_SIGNATURE_ENTRY(TYPE, NAME) \ + -(TYPE)get##NAME; \ + -(void)set##NAME : (TYPE)value; \ + -(TYPE)get##NAME##AtIndex : (NSUInteger)index; + +GPB_MESSAGE_SIGNATURE_ENTRY(BOOL, Bool) +GPB_MESSAGE_SIGNATURE_ENTRY(uint32_t, Fixed32) +GPB_MESSAGE_SIGNATURE_ENTRY(int32_t, SFixed32) +GPB_MESSAGE_SIGNATURE_ENTRY(float, Float) +GPB_MESSAGE_SIGNATURE_ENTRY(uint64_t, Fixed64) +GPB_MESSAGE_SIGNATURE_ENTRY(int64_t, SFixed64) +GPB_MESSAGE_SIGNATURE_ENTRY(double, Double) +GPB_MESSAGE_SIGNATURE_ENTRY(int32_t, Int32) +GPB_MESSAGE_SIGNATURE_ENTRY(int64_t, Int64) +GPB_MESSAGE_SIGNATURE_ENTRY(int32_t, SInt32) +GPB_MESSAGE_SIGNATURE_ENTRY(int64_t, SInt64) +GPB_MESSAGE_SIGNATURE_ENTRY(uint32_t, UInt32) +GPB_MESSAGE_SIGNATURE_ENTRY(uint64_t, UInt64) +GPB_MESSAGE_SIGNATURE_ENTRY(NSData *, Data) +GPB_MESSAGE_SIGNATURE_ENTRY(NSString *, String) +GPB_MESSAGE_SIGNATURE_ENTRY(GPBMessage *, Message) +GPB_MESSAGE_SIGNATURE_ENTRY(GPBMessage *, Group) +GPB_MESSAGE_SIGNATURE_ENTRY(int32_t, Enum) + +#undef GPB_MESSAGE_SIGNATURE_ENTRY + +- (id)getArray; +- (void)setArray:(NSArray *)array; ++ (id)getClassValue; +@end + +CF_EXTERN_C_END diff --git a/objectivec/GPBWellKnownTypes.h b/objectivec/GPBWellKnownTypes.h new file mode 100644 index 00000000..321cdc3e --- /dev/null +++ b/objectivec/GPBWellKnownTypes.h @@ -0,0 +1,48 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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. + +#import <Foundation/Foundation.h> + +#import "google/protobuf/Timestamp.pbobjc.h" +#import "google/protobuf/Duration.pbobjc.h" + +// Extension to GPBTimestamp to work with standard Foundation time/date types. +@interface GPBTimestamp (GBPWellKnownTypes) +@property(nonatomic, readwrite, strong) NSDate *date; +@property(nonatomic, readwrite) NSTimeInterval timeIntervalSince1970; +- (instancetype)initWithDate:(NSDate *)date; +- (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970; +@end + +// Extension to GPBDuration to work with standard Foundation time type. +@interface GPBDuration (GBPWellKnownTypes) +@property(nonatomic, readwrite) NSTimeInterval timeIntervalSince1970; +- (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970; +@end diff --git a/objectivec/GPBWellKnownTypes.m b/objectivec/GPBWellKnownTypes.m new file mode 100644 index 00000000..fe02f5de --- /dev/null +++ b/objectivec/GPBWellKnownTypes.m @@ -0,0 +1,117 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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. + +// Importing sources here to force the linker to include our category methods in +// the static library. If these were compiled separately, the category methods +// below would be stripped by the linker. + +#import "google/protobuf/Timestamp.pbobjc.m" +#import "google/protobuf/Duration.pbobjc.m" +#import "GPBWellKnownTypes.h" + +static NSTimeInterval TimeIntervalSince1970FromSecondsAndNanos(int64_t seconds, + int32_t nanos) { + return seconds + (NSTimeInterval)nanos / 1e9; +} + +static int32_t SecondsAndNanosFromTimeIntervalSince1970(NSTimeInterval time, + int64_t *outSeconds) { + NSTimeInterval seconds; + NSTimeInterval nanos = modf(time, &seconds); + nanos *= 1e9; + *outSeconds = (int64_t)seconds; + return (int32_t)nanos; +} + +@implementation GPBTimestamp (GBPWellKnownTypes) + +- (instancetype)initWithDate:(NSDate *)date { + return [self initWithTimeIntervalSince1970:date.timeIntervalSince1970]; +} + +- (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 { + if ((self = [super init])) { + int64_t seconds; + int32_t nanos = SecondsAndNanosFromTimeIntervalSince1970( + timeIntervalSince1970, &seconds); + self.seconds = seconds; + self.nanos = nanos; + } + return self; +} + +- (NSDate *)date { + return [NSDate dateWithTimeIntervalSince1970:self.timeIntervalSince1970]; +} + +- (void)setDate:(NSDate *)date { + self.timeIntervalSince1970 = date.timeIntervalSince1970; +} + +- (NSTimeInterval)timeIntervalSince1970 { + return TimeIntervalSince1970FromSecondsAndNanos(self.seconds, self.nanos); +} + +- (void)setTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 { + int64_t seconds; + int32_t nanos = + SecondsAndNanosFromTimeIntervalSince1970(timeIntervalSince1970, &seconds); + self.seconds = seconds; + self.nanos = nanos; +} + +@end + +@implementation GPBDuration (GBPWellKnownTypes) + +- (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 { + if ((self = [super init])) { + int64_t seconds; + int32_t nanos = SecondsAndNanosFromTimeIntervalSince1970( + timeIntervalSince1970, &seconds); + self.seconds = seconds; + self.nanos = nanos; + } + return self; +} + +- (NSTimeInterval)timeIntervalSince1970 { + return TimeIntervalSince1970FromSecondsAndNanos(self.seconds, self.nanos); +} + +- (void)setTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 { + int64_t seconds; + int32_t nanos = + SecondsAndNanosFromTimeIntervalSince1970(timeIntervalSince1970, &seconds); + self.seconds = seconds; + self.nanos = nanos; +} + +@end diff --git a/objectivec/GPBWireFormat.h b/objectivec/GPBWireFormat.h new file mode 100644 index 00000000..55f2edfc --- /dev/null +++ b/objectivec/GPBWireFormat.h @@ -0,0 +1,68 @@ +// 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. + +#import "GPBTypes.h" + +CF_EXTERN_C_BEGIN + +typedef enum { + GPBWireFormatVarint = 0, + GPBWireFormatFixed64 = 1, + GPBWireFormatLengthDelimited = 2, + GPBWireFormatStartGroup = 3, + GPBWireFormatEndGroup = 4, + GPBWireFormatFixed32 = 5, +} GPBWireFormat; + +enum { + GPBWireFormatMessageSetItem = 1, + GPBWireFormatMessageSetTypeId = 2, + GPBWireFormatMessageSetMessage = 3 +}; + +uint32_t GPBWireFormatMakeTag(uint32_t fieldNumber, GPBWireFormat wireType) + __attribute__((const)); +GPBWireFormat GPBWireFormatGetTagWireType(uint32_t tag) __attribute__((const)); +uint32_t GPBWireFormatGetTagFieldNumber(uint32_t tag) __attribute__((const)); + +GPBWireFormat GPBWireFormatForType(GPBType type, BOOL isPacked) + __attribute__((const)); + +#define GPBWireFormatMessageSetItemTag \ + (GPBWireFormatMakeTag(GPBWireFormatMessageSetItem, GPBWireFormatStartGroup)) +#define GPBWireFormatMessageSetItemEndTag \ + (GPBWireFormatMakeTag(GPBWireFormatMessageSetItem, GPBWireFormatEndGroup)) +#define GPBWireFormatMessageSetTypeIdTag \ + (GPBWireFormatMakeTag(GPBWireFormatMessageSetTypeId, GPBWireFormatVarint)) +#define GPBWireFormatMessageSetMessageTag \ + (GPBWireFormatMakeTag(GPBWireFormatMessageSetMessage, \ + GPBWireFormatLengthDelimited)) + +CF_EXTERN_C_END diff --git a/objectivec/GPBWireFormat.m b/objectivec/GPBWireFormat.m new file mode 100644 index 00000000..7435221f --- /dev/null +++ b/objectivec/GPBWireFormat.m @@ -0,0 +1,78 @@ +// 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. + +#import "GPBWireFormat.h" + +#import "GPBUtilities_PackagePrivate.h" + +enum { + GPBWireFormatTagTypeBits = 3, + GPBWireFormatTagTypeMask = 7 /* = (1 << GPBWireFormatTagTypeBits) - 1 */, +}; + +uint32_t GPBWireFormatMakeTag(uint32_t fieldNumber, GPBWireFormat wireType) { + return (fieldNumber << GPBWireFormatTagTypeBits) | wireType; +} + +GPBWireFormat GPBWireFormatGetTagWireType(uint32_t tag) { + return (GPBWireFormat)(tag & GPBWireFormatTagTypeMask); +} + +uint32_t GPBWireFormatGetTagFieldNumber(uint32_t tag) { + return GPBLogicalRightShift32(tag, GPBWireFormatTagTypeBits); +} + +GPBWireFormat GPBWireFormatForType(GPBType type, BOOL isPacked) { + if (isPacked) { + return GPBWireFormatLengthDelimited; + } + + static const GPBWireFormat format[GPBTypeCount] = { + GPBWireFormatVarint, // GPBTypeBool + GPBWireFormatFixed32, // GPBTypeFixed32 + GPBWireFormatFixed32, // GPBTypeSFixed32 + GPBWireFormatFixed32, // GPBTypeFloat + GPBWireFormatFixed64, // GPBTypeFixed64 + GPBWireFormatFixed64, // GPBTypeSFixed64 + GPBWireFormatFixed64, // GPBTypeDouble + GPBWireFormatVarint, // GPBTypeInt32 + GPBWireFormatVarint, // GPBTypeInt64 + GPBWireFormatVarint, // GPBTypeSInt32 + GPBWireFormatVarint, // GPBTypeSInt64 + GPBWireFormatVarint, // GPBTypeUInt32 + GPBWireFormatVarint, // GPBTypeUInt64 + GPBWireFormatLengthDelimited, // GPBTypeBytes + GPBWireFormatLengthDelimited, // GPBTypeString + GPBWireFormatLengthDelimited, // GPBTypeMessage + GPBWireFormatStartGroup, // GPBTypeGroup + GPBWireFormatVarint // GPBTypeEnum + }; + return format[type]; +} diff --git a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj new file mode 100644 index 00000000..46416043 --- /dev/null +++ b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj @@ -0,0 +1,919 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 47; + objects = { + +/* Begin PBXAggregateTarget section */ + 8BD3981414BE4AE70081D629 /* Compile_Protos */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 8BD3981714BE4AE70081D629 /* Build configuration list for PBXAggregateTarget "Compile_Protos" */; + buildPhases = ( + 8BD3981814BE4AF30081D629 /* ShellScript */, + ); + dependencies = ( + ); + name = Compile_Protos; + productName = Compile_Protos; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 2CFB390415C718CE00CBF84D /* Descriptor.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */; }; + 5102DABC1891A073002037B6 /* GPBConcurrencyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5102DABB1891A052002037B6 /* GPBConcurrencyTests.m */; }; + 7461B5360F94FB4600A0C422 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; + 7461B53C0F94FB4E00A0C422 /* GPBCodedInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B48F0F94F99000A0C422 /* GPBCodedInputStream.m */; }; + 7461B53D0F94FB4E00A0C422 /* GPBCodedOutputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4910F94F99000A0C422 /* GPBCodedOutputStream.m */; }; + 7461B5490F94FB4E00A0C422 /* GPBExtensionRegistry.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4A90F94F99000A0C422 /* GPBExtensionRegistry.m */; }; + 7461B54C0F94FB4E00A0C422 /* GPBField.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4AF0F94F99000A0C422 /* GPBField.m */; }; + 7461B5530F94FB4E00A0C422 /* GPBMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4BF0F94F99000A0C422 /* GPBMessage.m */; }; + 7461B5610F94FB4E00A0C422 /* GPBUnknownFieldSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4E20F94F99000A0C422 /* GPBUnknownFieldSet.m */; }; + 7461B5630F94FB4E00A0C422 /* GPBUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4E60F94F99000A0C422 /* GPBUtilities.m */; }; + 7461B5640F94FB4E00A0C422 /* GPBWireFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4E80F94F99000A0C422 /* GPBWireFormat.m */; }; + 8B210CCE159383D60032D72D /* golden_message in Resources */ = {isa = PBXBuildFile; fileRef = 8B210CCD159383D60032D72D /* golden_message */; }; + 8B210CD0159386920032D72D /* golden_packed_fields_message in Resources */ = {isa = PBXBuildFile; fileRef = 8B210CCF159386920032D72D /* golden_packed_fields_message */; }; + 8B4248BB1A8C256A00BC1EC6 /* GPBSwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B4248BA1A8C256A00BC1EC6 /* GPBSwiftTests.swift */; }; + 8B4248D21A927E1500BC1EC6 /* GPBWellKnownTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B4248D01A927E1500BC1EC6 /* GPBWellKnownTypes.m */; }; + 8B4248DC1A92933A00BC1EC6 /* GPBWellKnownTypesTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B4248DB1A92933A00BC1EC6 /* GPBWellKnownTypesTest.m */; }; + 8B79657B14992E3F002FFBFC /* GPBRootObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B79657914992E3E002FFBFC /* GPBRootObject.m */; }; + 8B79657D14992E3F002FFBFC /* GPBRootObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B79657914992E3E002FFBFC /* GPBRootObject.m */; }; + 8B8B615D17DF7056002EE618 /* GPBARCUnittestProtos.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B8B615C17DF7056002EE618 /* GPBARCUnittestProtos.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; }; + 8B96157414C8C38C00A2AC0B /* GPBDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B96157314C8C38C00A2AC0B /* GPBDescriptor.m */; }; + 8B96157514CA019D00A2AC0B /* Descriptor.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */; }; + 8BA9364518DA5F4C0056FA2A /* GPBStringTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */; }; + 8BBEA4A9147C727D00C4ADB7 /* GPBCodedInputStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B69B0F94FDF800A0C422 /* GPBCodedInputStreamTests.m */; }; + 8BBEA4AA147C727D00C4ADB7 /* GPBCodedOuputStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B69D0F94FDF800A0C422 /* GPBCodedOuputStreamTests.m */; }; + 8BBEA4AC147C727D00C4ADB7 /* GPBMessageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6A30F94FDF800A0C422 /* GPBMessageTests.m */; }; + 8BBEA4B0147C727D00C4ADB7 /* GPBTestUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */; }; + 8BBEA4B6147C727D00C4ADB7 /* GPBUnknownFieldSetTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6B80F94FDF900A0C422 /* GPBUnknownFieldSetTest.m */; }; + 8BBEA4B7147C727D00C4ADB7 /* GPBUtilitiesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6BA0F94FDF900A0C422 /* GPBUtilitiesTests.m */; }; + 8BBEA4B8147C727D00C4ADB7 /* GPBWireFormatTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6BC0F94FDF900A0C422 /* GPBWireFormatTests.m */; }; + 8BBEA4BB147C729200C4ADB7 /* libProtocolBuffers.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7461B52E0F94FAF800A0C422 /* libProtocolBuffers.a */; }; + 8BCC29BF16FD09A000F29F4A /* GPBFilteredMessageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BCC29BE16FD09A000F29F4A /* GPBFilteredMessageTests.m */; }; + 8BD3981F14BE59D70081D629 /* GPBUnittestProtos.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */; }; + 8BF8193514A0DDA600A2C982 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; + F401DC2D1A8D444600FCC765 /* GPBArray.m in Sources */ = {isa = PBXBuildFile; fileRef = F401DC2B1A8D444600FCC765 /* GPBArray.m */; }; + F401DC331A8E5C0200FCC765 /* GPBArrayTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F401DC321A8E5C0200FCC765 /* GPBArrayTests.m */; }; + F41C175D1833D3310064ED4D /* GPBPerfTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F41C175C1833D3310064ED4D /* GPBPerfTests.m */; }; + F4353D1D1AB8822D005A6198 /* GPBDescriptorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D1C1AB8822D005A6198 /* GPBDescriptorTests.m */; }; + F4353D231ABB1537005A6198 /* GPBDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D211ABB1537005A6198 /* GPBDictionary.m */; }; + F4353D341AC06F10005A6198 /* GPBDictionaryTests+Bool.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D2D1AC06F10005A6198 /* GPBDictionaryTests+Bool.m */; }; + F4353D351AC06F10005A6198 /* GPBDictionaryTests+Int32.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D2E1AC06F10005A6198 /* GPBDictionaryTests+Int32.m */; }; + F4353D361AC06F10005A6198 /* GPBDictionaryTests+Int64.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D2F1AC06F10005A6198 /* GPBDictionaryTests+Int64.m */; }; + F4353D371AC06F10005A6198 /* GPBDictionaryTests+String.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D301AC06F10005A6198 /* GPBDictionaryTests+String.m */; }; + F4353D381AC06F10005A6198 /* GPBDictionaryTests+UInt32.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D311AC06F10005A6198 /* GPBDictionaryTests+UInt32.m */; }; + F4353D391AC06F10005A6198 /* GPBDictionaryTests+UInt64.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D321AC06F10005A6198 /* GPBDictionaryTests+UInt64.m */; }; + F43C88D0191D77FC009E917D /* text_format_unittest_data.txt in Resources */ = {isa = PBXBuildFile; fileRef = F43C88CF191D77FC009E917D /* text_format_unittest_data.txt */; }; + F4487C4D1A9F8E0200531423 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; + F4487C521A9F8E4D00531423 /* GPBProtocolBuffers.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BCF338814ED799900BC5317 /* GPBProtocolBuffers.m */; }; + F4487C751AADF7F500531423 /* GPBMessageTests+Runtime.m in Sources */ = {isa = PBXBuildFile; fileRef = F4487C741AADF7F500531423 /* GPBMessageTests+Runtime.m */; }; + F4487C7F1AAF62CD00531423 /* GPBMessageTests+Serialization.m in Sources */ = {isa = PBXBuildFile; fileRef = F4487C7E1AAF62CD00531423 /* GPBMessageTests+Serialization.m */; }; + F4487C831AAF6AB300531423 /* GPBMessageTests+Merge.m in Sources */ = {isa = PBXBuildFile; fileRef = F4487C821AAF6AB300531423 /* GPBMessageTests+Merge.m */; }; + F45C69CC16DFD08D0081955B /* GPBExtensionField.m in Sources */ = {isa = PBXBuildFile; fileRef = F45C69CB16DFD08D0081955B /* GPBExtensionField.m */; }; + F45E57C71AE6DC6A000B7D99 /* text_format_map_unittest_data.txt in Resources */ = {isa = PBXBuildFile; fileRef = F45E57C61AE6DC6A000B7D99 /* text_format_map_unittest_data.txt */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 8BBEA4BC147C729A00C4ADB7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 7461B52D0F94FAF800A0C422; + remoteInfo = ProtocolBuffers; + }; + 8BD3982014BE59EB0081D629 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8BD3981414BE4AE70081D629; + remoteInfo = Compile_Protos; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 5102DABB1891A052002037B6 /* GPBConcurrencyTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GPBConcurrencyTests.m; sourceTree = "<group>"; }; + 51457B5F18D0B7AF00CCC606 /* GPBCodedInputStream_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBCodedInputStream_PackagePrivate.h; sourceTree = "<group>"; }; + 515B840C18B7DEE30031753B /* GPBDescriptor_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBDescriptor_PackagePrivate.h; sourceTree = "<group>"; }; + 5196A06918CE16B000B759E2 /* GPBMessage_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBMessage_PackagePrivate.h; sourceTree = "<group>"; }; + 7401C1A90F950347006D8281 /* UnitTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "UnitTests-Info.plist"; sourceTree = "<group>"; }; + 7461B48D0F94F99000A0C422 /* GPBBootstrap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBBootstrap.h; sourceTree = "<group>"; }; + 7461B48E0F94F99000A0C422 /* GPBCodedInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBCodedInputStream.h; sourceTree = "<group>"; }; + 7461B48F0F94F99000A0C422 /* GPBCodedInputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = GPBCodedInputStream.m; sourceTree = "<group>"; }; + 7461B4900F94F99000A0C422 /* GPBCodedOutputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBCodedOutputStream.h; sourceTree = "<group>"; }; + 7461B4910F94F99000A0C422 /* GPBCodedOutputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBCodedOutputStream.m; sourceTree = "<group>"; }; + 7461B4A80F94F99000A0C422 /* GPBExtensionRegistry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBExtensionRegistry.h; sourceTree = "<group>"; }; + 7461B4A90F94F99000A0C422 /* GPBExtensionRegistry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBExtensionRegistry.m; sourceTree = "<group>"; }; + 7461B4AE0F94F99000A0C422 /* GPBField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBField.h; sourceTree = "<group>"; }; + 7461B4AF0F94F99000A0C422 /* GPBField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBField.m; sourceTree = "<group>"; }; + 7461B4BE0F94F99000A0C422 /* GPBMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBMessage.h; sourceTree = "<group>"; }; + 7461B4BF0F94F99000A0C422 /* GPBMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBMessage.m; sourceTree = "<group>"; }; + 7461B4CD0F94F99000A0C422 /* GPBProtocolBuffers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBProtocolBuffers.h; sourceTree = "<group>"; }; + 7461B4E10F94F99000A0C422 /* GPBUnknownFieldSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBUnknownFieldSet.h; sourceTree = "<group>"; }; + 7461B4E20F94F99000A0C422 /* GPBUnknownFieldSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnknownFieldSet.m; sourceTree = "<group>"; }; + 7461B4E50F94F99000A0C422 /* GPBUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBUtilities.h; sourceTree = "<group>"; }; + 7461B4E60F94F99000A0C422 /* GPBUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUtilities.m; sourceTree = "<group>"; }; + 7461B4E70F94F99000A0C422 /* GPBWireFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBWireFormat.h; sourceTree = "<group>"; }; + 7461B4E80F94F99000A0C422 /* GPBWireFormat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBWireFormat.m; sourceTree = "<group>"; }; + 7461B52E0F94FAF800A0C422 /* libProtocolBuffers.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libProtocolBuffers.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 7461B69B0F94FDF800A0C422 /* GPBCodedInputStreamTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBCodedInputStreamTests.m; sourceTree = "<group>"; }; + 7461B69D0F94FDF800A0C422 /* GPBCodedOuputStreamTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBCodedOuputStreamTests.m; sourceTree = "<group>"; }; + 7461B6A30F94FDF800A0C422 /* GPBMessageTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBMessageTests.m; sourceTree = "<group>"; }; + 7461B6AB0F94FDF800A0C422 /* GPBTestUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBTestUtilities.h; sourceTree = "<group>"; }; + 7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBTestUtilities.m; sourceTree = "<group>"; }; + 7461B6B80F94FDF900A0C422 /* GPBUnknownFieldSetTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnknownFieldSetTest.m; sourceTree = "<group>"; }; + 7461B6BA0F94FDF900A0C422 /* GPBUtilitiesTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUtilitiesTests.m; sourceTree = "<group>"; }; + 7461B6BC0F94FDF900A0C422 /* GPBWireFormatTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBWireFormatTests.m; sourceTree = "<group>"; }; + 748F0CAF0FD70602000858A9 /* GPBExtensionField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBExtensionField.h; sourceTree = "<group>"; }; + 8B09AAF614B663A7007B4184 /* unittest_objc.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_objc.proto; sourceTree = "<group>"; }; + 8B20A9A816F1BBFA00BE3EAD /* Filter1.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = Filter1.txt; sourceTree = "<group>"; }; + 8B20A9A916F1BC0600BE3EAD /* unittest_filter.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_filter.proto; sourceTree = "<group>"; }; + 8B210CCD159383D60032D72D /* golden_message */ = {isa = PBXFileReference; lastKnownFileType = file; path = golden_message; sourceTree = "<group>"; }; + 8B210CCF159386920032D72D /* golden_packed_fields_message */ = {isa = PBXFileReference; lastKnownFileType = file; path = golden_packed_fields_message; sourceTree = "<group>"; }; + 8B4248B81A8C254000BC1EC6 /* protobuf */ = {isa = PBXFileReference; lastKnownFileType = text; name = protobuf; path = ../../Intermediates/ProtocolBuffers_OSX.build/DerivedSources/protos/google/protobuf; sourceTree = BUILT_PRODUCTS_DIR; }; + 8B4248B91A8C256900BC1EC6 /* UnitTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UnitTests-Bridging-Header.h"; sourceTree = "<group>"; }; + 8B4248BA1A8C256A00BC1EC6 /* GPBSwiftTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GPBSwiftTests.swift; sourceTree = "<group>"; }; + 8B4248CF1A927E1500BC1EC6 /* GPBWellKnownTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBWellKnownTypes.h; sourceTree = "<group>"; }; + 8B4248D01A927E1500BC1EC6 /* GPBWellKnownTypes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBWellKnownTypes.m; sourceTree = "<group>"; }; + 8B4248D31A92826400BC1EC6 /* Duration.pbobjc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Duration.pbobjc.h; path = google/protobuf/Duration.pbobjc.h; sourceTree = "<group>"; }; + 8B4248D41A92826400BC1EC6 /* Duration.pbobjc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Duration.pbobjc.m; path = google/protobuf/Duration.pbobjc.m; sourceTree = "<group>"; }; + 8B4248D51A92826400BC1EC6 /* Timestamp.pbobjc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Timestamp.pbobjc.h; path = google/protobuf/Timestamp.pbobjc.h; sourceTree = "<group>"; }; + 8B4248D61A92826400BC1EC6 /* Timestamp.pbobjc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Timestamp.pbobjc.m; path = google/protobuf/Timestamp.pbobjc.m; sourceTree = "<group>"; }; + 8B4248DB1A92933A00BC1EC6 /* GPBWellKnownTypesTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBWellKnownTypesTest.m; sourceTree = "<group>"; }; + 8B42494B1A92A16600BC1EC6 /* descriptor.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = descriptor.proto; path = ../src/google/protobuf/descriptor.proto; sourceTree = "<group>"; }; + 8B42494C1A92A16600BC1EC6 /* duration.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = duration.proto; path = ../src/google/protobuf/duration.proto; sourceTree = "<group>"; }; + 8B42494D1A92A16600BC1EC6 /* timestamp.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = timestamp.proto; path = ../src/google/protobuf/timestamp.proto; sourceTree = "<group>"; }; + 8B54585814DCC34E003D7338 /* Descriptor.pbobjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Descriptor.pbobjc.h; path = google/protobuf/Descriptor.pbobjc.h; sourceTree = SOURCE_ROOT; }; + 8B79657814992E3E002FFBFC /* GPBRootObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBRootObject.h; sourceTree = "<group>"; }; + 8B79657914992E3E002FFBFC /* GPBRootObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBRootObject.m; sourceTree = "<group>"; }; + 8B7E6A7414893DBA00F8884A /* unittest_custom_options.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_custom_options.proto; path = ../../src/google/protobuf/unittest_custom_options.proto; sourceTree = "<group>"; }; + 8B7E6A7514893DBA00F8884A /* unittest_embed_optimize_for.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_embed_optimize_for.proto; path = ../../src/google/protobuf/unittest_embed_optimize_for.proto; sourceTree = "<group>"; }; + 8B7E6A7614893DBA00F8884A /* unittest_empty.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_empty.proto; path = ../../src/google/protobuf/unittest_empty.proto; sourceTree = "<group>"; }; + 8B7E6A7814893DBB00F8884A /* unittest_import.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_import.proto; path = ../../src/google/protobuf/unittest_import.proto; sourceTree = "<group>"; }; + 8B7E6A7B14893DBC00F8884A /* unittest_mset.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_mset.proto; path = ../../src/google/protobuf/unittest_mset.proto; sourceTree = "<group>"; }; + 8B7E6A7C14893DBC00F8884A /* unittest_no_generic_services.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_no_generic_services.proto; path = ../../src/google/protobuf/unittest_no_generic_services.proto; sourceTree = "<group>"; }; + 8B7E6A7D14893DBC00F8884A /* unittest_optimize_for.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_optimize_for.proto; path = ../../src/google/protobuf/unittest_optimize_for.proto; sourceTree = "<group>"; }; + 8B7E6A7E14893DBC00F8884A /* unittest.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest.proto; path = ../../src/google/protobuf/unittest.proto; sourceTree = "<group>"; }; + 8B8B615C17DF7056002EE618 /* GPBARCUnittestProtos.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBARCUnittestProtos.m; sourceTree = "<group>"; }; + 8B96157214C8B06000A2AC0B /* GPBDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBDescriptor.h; sourceTree = "<group>"; }; + 8B96157314C8C38C00A2AC0B /* GPBDescriptor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBDescriptor.m; sourceTree = "<group>"; }; + 8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBStringTests.m; sourceTree = "<group>"; }; + 8BBD9DB016DD1DC8008E1EC1 /* unittest_lite.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_lite.proto; path = ../../src/google/protobuf/unittest_lite.proto; sourceTree = "<group>"; }; + 8BBEA4A6147C727100C4ADB7 /* UnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 8BCC29BE16FD09A000F29F4A /* GPBFilteredMessageTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBFilteredMessageTests.m; sourceTree = "<group>"; }; + 8BCF338814ED799900BC5317 /* GPBProtocolBuffers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GPBProtocolBuffers.m; sourceTree = "<group>"; }; + 8BD3981D14BE54220081D629 /* unittest_enormous_descriptor.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_enormous_descriptor.proto; path = ../../src/google/protobuf/unittest_enormous_descriptor.proto; sourceTree = "<group>"; }; + 8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnittestProtos.m; sourceTree = "<group>"; }; + 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Descriptor.pbobjc.m; path = google/protobuf/Descriptor.pbobjc.m; sourceTree = SOURCE_ROOT; }; + 8BEB5AE01498033E0078BF9D /* GPBTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBTypes.h; sourceTree = "<group>"; }; + F401DC2A1A8D444600FCC765 /* GPBArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBArray.h; sourceTree = "<group>"; }; + F401DC2B1A8D444600FCC765 /* GPBArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBArray.m; sourceTree = "<group>"; }; + F401DC321A8E5C0200FCC765 /* GPBArrayTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBArrayTests.m; sourceTree = "<group>"; }; + F41C175C1833D3310064ED4D /* GPBPerfTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBPerfTests.m; sourceTree = "<group>"; }; + F4353D1C1AB8822D005A6198 /* GPBDescriptorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBDescriptorTests.m; sourceTree = "<group>"; }; + F4353D201ABB1537005A6198 /* GPBDictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBDictionary.h; sourceTree = "<group>"; }; + F4353D211ABB1537005A6198 /* GPBDictionary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBDictionary.m; sourceTree = "<group>"; }; + F4353D2C1AC06F10005A6198 /* GPBDictionaryTests.pddm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = GPBDictionaryTests.pddm; sourceTree = "<group>"; }; + F4353D2D1AC06F10005A6198 /* GPBDictionaryTests+Bool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+Bool.m"; sourceTree = "<group>"; }; + F4353D2E1AC06F10005A6198 /* GPBDictionaryTests+Int32.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+Int32.m"; sourceTree = "<group>"; }; + F4353D2F1AC06F10005A6198 /* GPBDictionaryTests+Int64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+Int64.m"; sourceTree = "<group>"; }; + F4353D301AC06F10005A6198 /* GPBDictionaryTests+String.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+String.m"; sourceTree = "<group>"; }; + F4353D311AC06F10005A6198 /* GPBDictionaryTests+UInt32.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+UInt32.m"; sourceTree = "<group>"; }; + F4353D321AC06F10005A6198 /* GPBDictionaryTests+UInt64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+UInt64.m"; sourceTree = "<group>"; }; + F43725911AC9832D004DCAFB /* GPBDictionary_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBDictionary_PackagePrivate.h; sourceTree = "<group>"; }; + F43C88CF191D77FC009E917D /* text_format_unittest_data.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = text_format_unittest_data.txt; sourceTree = "<group>"; }; + F4411BE71AF12FD700324B4A /* GPBArray_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBArray_PackagePrivate.h; sourceTree = "<group>"; }; + F4487C511A9F8E0200531423 /* libTestSingleSourceBuild.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libTestSingleSourceBuild.a; sourceTree = BUILT_PRODUCTS_DIR; }; + F4487C741AADF7F500531423 /* GPBMessageTests+Runtime.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBMessageTests+Runtime.m"; sourceTree = "<group>"; }; + F4487C781AADFB3100531423 /* unittest_runtime_proto2.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_runtime_proto2.proto; sourceTree = "<group>"; }; + F4487C791AADFB3200531423 /* unittest_runtime_proto3.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_runtime_proto3.proto; sourceTree = "<group>"; }; + F4487C7C1AAE06AC00531423 /* GPBUtilities_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBUtilities_PackagePrivate.h; sourceTree = "<group>"; }; + F4487C7E1AAF62CD00531423 /* GPBMessageTests+Serialization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBMessageTests+Serialization.m"; sourceTree = "<group>"; }; + F4487C821AAF6AB300531423 /* GPBMessageTests+Merge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBMessageTests+Merge.m"; sourceTree = "<group>"; }; + F44B25D81A729803005CCF68 /* Filter2.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = Filter2.txt; sourceTree = "<group>"; }; + F451D3F51A8AAE8700B8A22C /* GPBProtocolBuffers_RuntimeSupport.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBProtocolBuffers_RuntimeSupport.h; sourceTree = "<group>"; }; + F45C69CB16DFD08D0081955B /* GPBExtensionField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBExtensionField.m; sourceTree = "<group>"; }; + F45E57C61AE6DC6A000B7D99 /* text_format_map_unittest_data.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = text_format_map_unittest_data.txt; sourceTree = "<group>"; }; + F4AC9E1D1A8BEB3500BD6E83 /* unittest_cycle.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_cycle.proto; sourceTree = "<group>"; }; + F4B6B8AF1A9CC98000892426 /* GPBField_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBField_PackagePrivate.h; sourceTree = "<group>"; }; + F4B6B8B21A9CCBDA00892426 /* GPBUnknownFieldSet_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBUnknownFieldSet_PackagePrivate.h; sourceTree = "<group>"; }; + F4B6B8B61A9CD1DE00892426 /* GPBExtensionField_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBExtensionField_PackagePrivate.h; sourceTree = "<group>"; }; + F4B6B8B71A9CD1DE00892426 /* GPBExtensionRegistry_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBExtensionRegistry_PackagePrivate.h; sourceTree = "<group>"; }; + F4B6B8B81A9CD1DE00892426 /* GPBRootObject_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBRootObject_PackagePrivate.h; sourceTree = "<group>"; }; + F4B6B8B91A9D338B00892426 /* unittest_name_mangling.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_name_mangling.proto; sourceTree = "<group>"; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 7461B52C0F94FAF800A0C422 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 7461B5360F94FB4600A0C422 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8BBEA4A3147C727100C4ADB7 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8BBEA4BB147C729200C4ADB7 /* libProtocolBuffers.a in Frameworks */, + 8BF8193514A0DDA600A2C982 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F4487C4C1A9F8E0200531423 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + F4487C4D1A9F8E0200531423 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 080E96DDFE201D6D7F000001 /* Core Source */ = { + isa = PBXGroup; + children = ( + 7461B4CD0F94F99000A0C422 /* GPBProtocolBuffers.h */, + F451D3F51A8AAE8700B8A22C /* GPBProtocolBuffers_RuntimeSupport.h */, + 8BCF338814ED799900BC5317 /* GPBProtocolBuffers.m */, + 7461B3C50F94F84100A0C422 /* Extensions */, + 7461B4850F94F96600A0C422 /* Fields */, + 7461B4860F94F96B00A0C422 /* IO */, + 7461B5150F94FA7300A0C422 /* Messages */, + 8BCF334414ED727300BC5317 /* Support */, + 29B97315FDCFA39411CA2CEA /* Generated */, + ); + name = "Core Source"; + sourceTree = "<group>"; + }; + 19C28FACFE9D520D11CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 7461B52E0F94FAF800A0C422 /* libProtocolBuffers.a */, + 8BBEA4A6147C727100C4ADB7 /* UnitTests.xctest */, + F4487C511A9F8E0200531423 /* libTestSingleSourceBuild.a */, + ); + name = Products; + sourceTree = "<group>"; + }; + 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { + isa = PBXGroup; + children = ( + 080E96DDFE201D6D7F000001 /* Core Source */, + 7461B6940F94FDDD00A0C422 /* Tests */, + 29B97323FDCFA39411CA2CEA /* Frameworks */, + 19C28FACFE9D520D11CA2CBB /* Products */, + ); + name = CustomTemplate; + sourceTree = "<group>"; + }; + 29B97315FDCFA39411CA2CEA /* Generated */ = { + isa = PBXGroup; + children = ( + 8B42494B1A92A16600BC1EC6 /* descriptor.proto */, + 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */, + 8B54585814DCC34E003D7338 /* Descriptor.pbobjc.h */, + 8B42494C1A92A16600BC1EC6 /* duration.proto */, + 8B4248D31A92826400BC1EC6 /* Duration.pbobjc.h */, + 8B4248D41A92826400BC1EC6 /* Duration.pbobjc.m */, + 8B42494D1A92A16600BC1EC6 /* timestamp.proto */, + 8B4248D51A92826400BC1EC6 /* Timestamp.pbobjc.h */, + 8B4248D61A92826400BC1EC6 /* Timestamp.pbobjc.m */, + ); + name = Generated; + sourceTree = "<group>"; + }; + 29B97323FDCFA39411CA2CEA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 1D30AB110D05D00D00671497 /* Foundation.framework */, + ); + name = Frameworks; + sourceTree = "<group>"; + }; + 7461B3C50F94F84100A0C422 /* Extensions */ = { + isa = PBXGroup; + children = ( + F4B6B8B61A9CD1DE00892426 /* GPBExtensionField_PackagePrivate.h */, + 748F0CAF0FD70602000858A9 /* GPBExtensionField.h */, + F45C69CB16DFD08D0081955B /* GPBExtensionField.m */, + F4B6B8B71A9CD1DE00892426 /* GPBExtensionRegistry_PackagePrivate.h */, + 7461B4A80F94F99000A0C422 /* GPBExtensionRegistry.h */, + 7461B4A90F94F99000A0C422 /* GPBExtensionRegistry.m */, + F4B6B8B81A9CD1DE00892426 /* GPBRootObject_PackagePrivate.h */, + 8B79657814992E3E002FFBFC /* GPBRootObject.h */, + 8B79657914992E3E002FFBFC /* GPBRootObject.m */, + ); + name = Extensions; + sourceTree = "<group>"; + }; + 7461B4850F94F96600A0C422 /* Fields */ = { + isa = PBXGroup; + children = ( + F4B6B8AF1A9CC98000892426 /* GPBField_PackagePrivate.h */, + 7461B4AE0F94F99000A0C422 /* GPBField.h */, + 7461B4AF0F94F99000A0C422 /* GPBField.m */, + F4B6B8B21A9CCBDA00892426 /* GPBUnknownFieldSet_PackagePrivate.h */, + 7461B4E10F94F99000A0C422 /* GPBUnknownFieldSet.h */, + 7461B4E20F94F99000A0C422 /* GPBUnknownFieldSet.m */, + ); + name = Fields; + sourceTree = "<group>"; + }; + 7461B4860F94F96B00A0C422 /* IO */ = { + isa = PBXGroup; + children = ( + 7461B48E0F94F99000A0C422 /* GPBCodedInputStream.h */, + 51457B5F18D0B7AF00CCC606 /* GPBCodedInputStream_PackagePrivate.h */, + 7461B48F0F94F99000A0C422 /* GPBCodedInputStream.m */, + 7461B4900F94F99000A0C422 /* GPBCodedOutputStream.h */, + 7461B4910F94F99000A0C422 /* GPBCodedOutputStream.m */, + 7461B4E70F94F99000A0C422 /* GPBWireFormat.h */, + 7461B4E80F94F99000A0C422 /* GPBWireFormat.m */, + ); + name = IO; + sourceTree = "<group>"; + }; + 7461B5150F94FA7300A0C422 /* Messages */ = { + isa = PBXGroup; + children = ( + 515B840C18B7DEE30031753B /* GPBDescriptor_PackagePrivate.h */, + 8B96157214C8B06000A2AC0B /* GPBDescriptor.h */, + 8B96157314C8C38C00A2AC0B /* GPBDescriptor.m */, + 7461B4BE0F94F99000A0C422 /* GPBMessage.h */, + 5196A06918CE16B000B759E2 /* GPBMessage_PackagePrivate.h */, + 7461B4BF0F94F99000A0C422 /* GPBMessage.m */, + ); + name = Messages; + sourceTree = "<group>"; + }; + 7461B6940F94FDDD00A0C422 /* Tests */ = { + isa = PBXGroup; + children = ( + 8B4248B81A8C254000BC1EC6 /* protobuf */, + 8B20A9A816F1BBFA00BE3EAD /* Filter1.txt */, + F44B25D81A729803005CCF68 /* Filter2.txt */, + 8B210CCD159383D60032D72D /* golden_message */, + 8B210CCF159386920032D72D /* golden_packed_fields_message */, + 8B8B615C17DF7056002EE618 /* GPBARCUnittestProtos.m */, + F401DC321A8E5C0200FCC765 /* GPBArrayTests.m */, + 7461B69B0F94FDF800A0C422 /* GPBCodedInputStreamTests.m */, + 7461B69D0F94FDF800A0C422 /* GPBCodedOuputStreamTests.m */, + 5102DABB1891A052002037B6 /* GPBConcurrencyTests.m */, + F4353D1C1AB8822D005A6198 /* GPBDescriptorTests.m */, + F4353D2C1AC06F10005A6198 /* GPBDictionaryTests.pddm */, + F4353D2D1AC06F10005A6198 /* GPBDictionaryTests+Bool.m */, + F4353D2E1AC06F10005A6198 /* GPBDictionaryTests+Int32.m */, + F4353D2F1AC06F10005A6198 /* GPBDictionaryTests+Int64.m */, + F4353D301AC06F10005A6198 /* GPBDictionaryTests+String.m */, + F4353D311AC06F10005A6198 /* GPBDictionaryTests+UInt32.m */, + F4353D321AC06F10005A6198 /* GPBDictionaryTests+UInt64.m */, + 8BCC29BE16FD09A000F29F4A /* GPBFilteredMessageTests.m */, + 7461B6A30F94FDF800A0C422 /* GPBMessageTests.m */, + F4487C821AAF6AB300531423 /* GPBMessageTests+Merge.m */, + F4487C741AADF7F500531423 /* GPBMessageTests+Runtime.m */, + F4487C7E1AAF62CD00531423 /* GPBMessageTests+Serialization.m */, + F41C175C1833D3310064ED4D /* GPBPerfTests.m */, + 8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */, + 8B4248BA1A8C256A00BC1EC6 /* GPBSwiftTests.swift */, + 7461B6AB0F94FDF800A0C422 /* GPBTestUtilities.h */, + 7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */, + 8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */, + 7461B6B80F94FDF900A0C422 /* GPBUnknownFieldSetTest.m */, + 7461B6BA0F94FDF900A0C422 /* GPBUtilitiesTests.m */, + 8B4248DB1A92933A00BC1EC6 /* GPBWellKnownTypesTest.m */, + 7461B6BC0F94FDF900A0C422 /* GPBWireFormatTests.m */, + F43C88CF191D77FC009E917D /* text_format_unittest_data.txt */, + F45E57C61AE6DC6A000B7D99 /* text_format_map_unittest_data.txt */, + 8B7E6A7414893DBA00F8884A /* unittest_custom_options.proto */, + F4AC9E1D1A8BEB3500BD6E83 /* unittest_cycle.proto */, + 8B7E6A7514893DBA00F8884A /* unittest_embed_optimize_for.proto */, + 8B7E6A7614893DBA00F8884A /* unittest_empty.proto */, + 8BD3981D14BE54220081D629 /* unittest_enormous_descriptor.proto */, + 8B20A9A916F1BC0600BE3EAD /* unittest_filter.proto */, + 8B7E6A7814893DBB00F8884A /* unittest_import.proto */, + 8BBD9DB016DD1DC8008E1EC1 /* unittest_lite.proto */, + 8B7E6A7B14893DBC00F8884A /* unittest_mset.proto */, + F4B6B8B91A9D338B00892426 /* unittest_name_mangling.proto */, + 8B7E6A7C14893DBC00F8884A /* unittest_no_generic_services.proto */, + 8B09AAF614B663A7007B4184 /* unittest_objc.proto */, + 8B7E6A7D14893DBC00F8884A /* unittest_optimize_for.proto */, + F4487C781AADFB3100531423 /* unittest_runtime_proto2.proto */, + F4487C791AADFB3200531423 /* unittest_runtime_proto3.proto */, + 8B7E6A7E14893DBC00F8884A /* unittest.proto */, + 8B4248B91A8C256900BC1EC6 /* UnitTests-Bridging-Header.h */, + 7401C1A90F950347006D8281 /* UnitTests-Info.plist */, + ); + path = Tests; + sourceTree = "<group>"; + }; + 8BCF334414ED727300BC5317 /* Support */ = { + isa = PBXGroup; + children = ( + F4411BE71AF12FD700324B4A /* GPBArray_PackagePrivate.h */, + F401DC2A1A8D444600FCC765 /* GPBArray.h */, + F401DC2B1A8D444600FCC765 /* GPBArray.m */, + 7461B48D0F94F99000A0C422 /* GPBBootstrap.h */, + F43725911AC9832D004DCAFB /* GPBDictionary_PackagePrivate.h */, + F4353D201ABB1537005A6198 /* GPBDictionary.h */, + F4353D211ABB1537005A6198 /* GPBDictionary.m */, + 8BEB5AE01498033E0078BF9D /* GPBTypes.h */, + F4487C7C1AAE06AC00531423 /* GPBUtilities_PackagePrivate.h */, + 7461B4E50F94F99000A0C422 /* GPBUtilities.h */, + 7461B4E60F94F99000A0C422 /* GPBUtilities.m */, + 8B4248CF1A927E1500BC1EC6 /* GPBWellKnownTypes.h */, + 8B4248D01A927E1500BC1EC6 /* GPBWellKnownTypes.m */, + ); + name = Support; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 7461B52A0F94FAF800A0C422 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F4487C391A9F8E0200531423 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 7461B52D0F94FAF800A0C422 /* ProtocolBuffers */ = { + isa = PBXNativeTarget; + buildConfigurationList = 7461B5330F94FAFD00A0C422 /* Build configuration list for PBXNativeTarget "ProtocolBuffers" */; + buildPhases = ( + 7461B52A0F94FAF800A0C422 /* Headers */, + 7461B52B0F94FAF800A0C422 /* Sources */, + 7461B52C0F94FAF800A0C422 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ProtocolBuffers; + productName = "ProtocolBuffers-iPhoneDevice"; + productReference = 7461B52E0F94FAF800A0C422 /* libProtocolBuffers.a */; + productType = "com.apple.product-type.library.static"; + }; + 8BBEA4A5147C727100C4ADB7 /* UnitTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8BBEA4BA147C728600C4ADB7 /* Build configuration list for PBXNativeTarget "UnitTests" */; + buildPhases = ( + F4B62A781AF91F6000AFCEDC /* Script: Check Runtime Stamps */, + 8BBEA4A1147C727100C4ADB7 /* Resources */, + 8BBEA4A2147C727100C4ADB7 /* Sources */, + 8BBEA4A3147C727100C4ADB7 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 8BBEA4BD147C729A00C4ADB7 /* PBXTargetDependency */, + 8BD3982114BE59EB0081D629 /* PBXTargetDependency */, + ); + name = UnitTests; + productName = UnitTests; + productReference = 8BBEA4A6147C727100C4ADB7 /* UnitTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + F4487C381A9F8E0200531423 /* TestSingleSourceBuild */ = { + isa = PBXNativeTarget; + buildConfigurationList = F4487C4E1A9F8E0200531423 /* Build configuration list for PBXNativeTarget "TestSingleSourceBuild" */; + buildPhases = ( + F4487C391A9F8E0200531423 /* Headers */, + F4487C3D1A9F8E0200531423 /* Sources */, + F4487C4C1A9F8E0200531423 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = TestSingleSourceBuild; + productName = "ProtocolBuffers-iPhoneDevice"; + productReference = F4487C511A9F8E0200531423 /* libTestSingleSourceBuild.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 29B97313FDCFA39411CA2CEA /* Project object */ = { + isa = PBXProject; + attributes = { + LastTestingUpgradeCheck = 0600; + LastUpgradeCheck = 0620; + TargetAttributes = { + 8BBEA4A5147C727100C4ADB7 = { + TestTargetID = 8B9A5EA41831993600A9D33B; + }; + }; + }; + buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "ProtocolBuffers_OSX" */; + compatibilityVersion = "Xcode 6.3"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + en, + ); + mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 7461B52D0F94FAF800A0C422 /* ProtocolBuffers */, + 8BBEA4A5147C727100C4ADB7 /* UnitTests */, + 8BD3981414BE4AE70081D629 /* Compile_Protos */, + F4487C381A9F8E0200531423 /* TestSingleSourceBuild */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8BBEA4A1147C727100C4ADB7 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8B210CCE159383D60032D72D /* golden_message in Resources */, + F43C88D0191D77FC009E917D /* text_format_unittest_data.txt in Resources */, + 8B210CD0159386920032D72D /* golden_packed_fields_message in Resources */, + F45E57C71AE6DC6A000B7D99 /* text_format_map_unittest_data.txt in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 8BD3981814BE4AF30081D629 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/../src/google/protobuf/unittest_custom_options.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_embed_optimize_for.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_empty.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_enormous_descriptor.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_import_lite.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_import.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_lite_imports_nonlite.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_lite.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_mset.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_no_generic_services.proto", + "$(SRCROOT)/../src/google/protobuf/unittest.proto", + "$(SRCROOT)/Tests/unittest_objc.proto", + "$(SRCROOT)/../src/.libs/libprotoc.10.dylib", + "$(SRCROOT)/../src/google/protobuf/unittest_import_public_lite.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_import_public.proto", + "$(SRCROOT)/Tests/unittest_filter.proto", + "$(SRCROOT)/../src/.libs/libprotobuf.10.dylib", + "$(SRCROOT)/../src/.libs/protoc", + "$(SRCROOT)/Tests/Filter1.txt", + "$(SRCROOT)/Tests/Filter2.txt", + "$(SRCROOT)/Tests/unittest_cycle.proto", + "$(SRCROOT)/Tests/unittest_name_mangling.proto", + "$(SRCROOT)/Tests/unittest_runtime_proto2.proto", + "$(SRCROOT)/Tests/unittest_runtime_proto3.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_drop_unknown_fields.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_preserve_unknown_enum.proto", + "$(SRCROOT)/../src/google/protobuf/map_lite_unittest.proto", + "$(SRCROOT)/../src/google/protobuf/map_proto2_unittest.proto", + "$(SRCROOT)/../src/google/protobuf/map_unittest.proto", + ); + outputPaths = ( + "$(PROJECT_DERIVED_FILE_DIR)/protos/google/protobuf/Unittest.pbobjc.h", + "$(PROJECT_DERIVED_FILE_DIR)/protos/google/protobuf/Unittest.pbobjc.m", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/bash; + shellScript = "set -eu\nmkdir -p \"${PROJECT_DERIVED_FILE_DIR}/protos\"\nexport PATH=\"${PATH}:.\"\ncd \"${SRCROOT}\"/../src\n\nPROTOC=./protoc\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_custom_options.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_enormous_descriptor.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_embed_optimize_for.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_empty.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import_lite.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_lite.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_mset.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_no_generic_services.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_optimize_for.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import_public.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import_public_lite.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_drop_unknown_fields.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_preserve_unknown_enum.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/map_lite_unittest.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/map_proto2_unittest.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/map_unittest.proto\n\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_objc.proto\n\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_cycle.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_name_mangling.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_runtime_proto2.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_runtime_proto3.proto\n\nexport GPB_CLASSLIST_PATH=\"${PROJECT_DERIVED_FILE_DIR}/ClassList.txt\"\nexport GPB_OBJC_CLASS_WHITELIST_PATHS=\"${SRCROOT}/Tests/Filter1.txt;${SRCROOT}/Tests/Filter2.txt\"\n\nif [ -e ${GPB_CLASSLIST_PATH} ]; then\nrm ${GPB_CLASSLIST_PATH}\nfi\n\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_filter.proto\n\n"; + showEnvVarsInLog = 0; + }; + F4B62A781AF91F6000AFCEDC /* Script: Check Runtime Stamps */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Script: Check Runtime Stamps"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "set -eu\nexec \"${SOURCE_ROOT}/DevTools/check_version_stamps.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 7461B52B0F94FAF800A0C422 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2CFB390415C718CE00CBF84D /* Descriptor.pbobjc.m in Sources */, + 7461B53C0F94FB4E00A0C422 /* GPBCodedInputStream.m in Sources */, + 7461B53D0F94FB4E00A0C422 /* GPBCodedOutputStream.m in Sources */, + F401DC2D1A8D444600FCC765 /* GPBArray.m in Sources */, + 7461B5490F94FB4E00A0C422 /* GPBExtensionRegistry.m in Sources */, + 7461B54C0F94FB4E00A0C422 /* GPBField.m in Sources */, + 7461B5530F94FB4E00A0C422 /* GPBMessage.m in Sources */, + 7461B5610F94FB4E00A0C422 /* GPBUnknownFieldSet.m in Sources */, + 7461B5630F94FB4E00A0C422 /* GPBUtilities.m in Sources */, + 7461B5640F94FB4E00A0C422 /* GPBWireFormat.m in Sources */, + F4353D231ABB1537005A6198 /* GPBDictionary.m in Sources */, + 8B79657B14992E3F002FFBFC /* GPBRootObject.m in Sources */, + 8B96157414C8C38C00A2AC0B /* GPBDescriptor.m in Sources */, + F45C69CC16DFD08D0081955B /* GPBExtensionField.m in Sources */, + 8B4248D21A927E1500BC1EC6 /* GPBWellKnownTypes.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8BBEA4A2147C727100C4ADB7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8BBEA4A9147C727D00C4ADB7 /* GPBCodedInputStreamTests.m in Sources */, + F401DC331A8E5C0200FCC765 /* GPBArrayTests.m in Sources */, + F4353D361AC06F10005A6198 /* GPBDictionaryTests+Int64.m in Sources */, + F4353D391AC06F10005A6198 /* GPBDictionaryTests+UInt64.m in Sources */, + 8BBEA4AA147C727D00C4ADB7 /* GPBCodedOuputStreamTests.m in Sources */, + 8BBEA4AC147C727D00C4ADB7 /* GPBMessageTests.m in Sources */, + F4487C7F1AAF62CD00531423 /* GPBMessageTests+Serialization.m in Sources */, + 8B4248DC1A92933A00BC1EC6 /* GPBWellKnownTypesTest.m in Sources */, + F4353D1D1AB8822D005A6198 /* GPBDescriptorTests.m in Sources */, + 8B4248BB1A8C256A00BC1EC6 /* GPBSwiftTests.swift in Sources */, + 5102DABC1891A073002037B6 /* GPBConcurrencyTests.m in Sources */, + F4487C751AADF7F500531423 /* GPBMessageTests+Runtime.m in Sources */, + F4353D351AC06F10005A6198 /* GPBDictionaryTests+Int32.m in Sources */, + 8BBEA4B0147C727D00C4ADB7 /* GPBTestUtilities.m in Sources */, + F41C175D1833D3310064ED4D /* GPBPerfTests.m in Sources */, + F4353D341AC06F10005A6198 /* GPBDictionaryTests+Bool.m in Sources */, + F4487C831AAF6AB300531423 /* GPBMessageTests+Merge.m in Sources */, + 8BA9364518DA5F4C0056FA2A /* GPBStringTests.m in Sources */, + 8BBEA4B6147C727D00C4ADB7 /* GPBUnknownFieldSetTest.m in Sources */, + F4353D371AC06F10005A6198 /* GPBDictionaryTests+String.m in Sources */, + F4353D381AC06F10005A6198 /* GPBDictionaryTests+UInt32.m in Sources */, + 8BBEA4B7147C727D00C4ADB7 /* GPBUtilitiesTests.m in Sources */, + 8BBEA4B8147C727D00C4ADB7 /* GPBWireFormatTests.m in Sources */, + 8B79657D14992E3F002FFBFC /* GPBRootObject.m in Sources */, + 8BD3981F14BE59D70081D629 /* GPBUnittestProtos.m in Sources */, + 8B96157514CA019D00A2AC0B /* Descriptor.pbobjc.m in Sources */, + 8BCC29BF16FD09A000F29F4A /* GPBFilteredMessageTests.m in Sources */, + 8B8B615D17DF7056002EE618 /* GPBARCUnittestProtos.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F4487C3D1A9F8E0200531423 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F4487C521A9F8E4D00531423 /* GPBProtocolBuffers.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 8BBEA4BD147C729A00C4ADB7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 7461B52D0F94FAF800A0C422 /* ProtocolBuffers */; + targetProxy = 8BBEA4BC147C729A00C4ADB7 /* PBXContainerItemProxy */; + }; + 8BD3982114BE59EB0081D629 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 8BD3981414BE4AE70081D629 /* Compile_Protos */; + targetProxy = 8BD3982014BE59EB0081D629 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 7461B52F0F94FAFA00A0C422 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + HEADER_SEARCH_PATHS = "$(SRCROOT)"; + PRODUCT_NAME = ProtocolBuffers; + }; + name = Debug; + }; + 7461B5300F94FAFA00A0C422 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + HEADER_SEARCH_PATHS = "$(SRCROOT)"; + PRODUCT_NAME = ProtocolBuffers; + }; + name = Release; + }; + 8BBEA4A7147C727100C4ADB7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + HEADER_SEARCH_PATHS = ( + "${PROJECT_DERIVED_FILE_DIR}/protos", + "$(SRCROOT)", + ); + INFOPLIST_FILE = "Tests/UnitTests-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_NAME = UnitTests; + SWIFT_OBJC_BRIDGING_HEADER = "Tests/UnitTests-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 8BBEA4A8147C727100C4ADB7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + HEADER_SEARCH_PATHS = ( + "${PROJECT_DERIVED_FILE_DIR}/protos", + "$(SRCROOT)", + ); + INFOPLIST_FILE = "Tests/UnitTests-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_NAME = UnitTests; + SWIFT_OBJC_BRIDGING_HEADER = "Tests/UnitTests-Bridging-Header.h"; + }; + name = Release; + }; + 8BD3981514BE4AE70081D629 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 8BD3981614BE4AE70081D629 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + C01FCF4F08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = YES; + CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES; + CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES; + CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES; + CLANG_STATIC_ANALYZER_MODE = deep; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; + CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES; + CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1"; + GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; + GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_MISSING_PARENTHESES = YES; + GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; + GCC_WARN_SHADOW = YES; + GCC_WARN_SIGN_COMPARE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_PARAMETER = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + GENERATE_PROFILING_CODE = NO; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + RUN_CLANG_STATIC_ANALYZER = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + C01FCF5008A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = YES; + CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES; + CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES; + CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES; + CLANG_STATIC_ANALYZER_MODE = deep; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; + CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES; + CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; + GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_MISSING_PARENTHESES = YES; + GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; + GCC_WARN_SHADOW = YES; + GCC_WARN_SIGN_COMPARE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_PARAMETER = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + GENERATE_PROFILING_CODE = NO; + MACOSX_DEPLOYMENT_TARGET = 10.9; + RUN_CLANG_STATIC_ANALYZER = YES; + SDKROOT = macosx; + }; + name = Release; + }; + F4487C4F1A9F8E0200531423 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + HEADER_SEARCH_PATHS = "$(SRCROOT)"; + PRODUCT_NAME = TestSingleSourceBuild; + }; + name = Debug; + }; + F4487C501A9F8E0200531423 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + HEADER_SEARCH_PATHS = "$(SRCROOT)"; + PRODUCT_NAME = TestSingleSourceBuild; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 7461B5330F94FAFD00A0C422 /* Build configuration list for PBXNativeTarget "ProtocolBuffers" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7461B52F0F94FAFA00A0C422 /* Debug */, + 7461B5300F94FAFA00A0C422 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8BBEA4BA147C728600C4ADB7 /* Build configuration list for PBXNativeTarget "UnitTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8BBEA4A7147C727100C4ADB7 /* Debug */, + 8BBEA4A8147C727100C4ADB7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8BD3981714BE4AE70081D629 /* Build configuration list for PBXAggregateTarget "Compile_Protos" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8BD3981514BE4AE70081D629 /* Debug */, + 8BD3981614BE4AE70081D629 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C01FCF4E08A954540054247B /* Build configuration list for PBXProject "ProtocolBuffers_OSX" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4F08A954540054247B /* Debug */, + C01FCF5008A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F4487C4E1A9F8E0200531423 /* Build configuration list for PBXNativeTarget "TestSingleSourceBuild" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F4487C4F1A9F8E0200531423 /* Debug */, + F4487C501A9F8E0200531423 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; +} diff --git a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..888be4da --- /dev/null +++ b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Workspace + version = "1.0"> + <FileRef + location = "self:ProtocolBuffers_OSX.xcodeproj"> + </FileRef> +</Workspace> diff --git a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..08de0be8 --- /dev/null +++ b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key> + <false/> +</dict> +</plist> diff --git a/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme b/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme new file mode 100644 index 00000000..7083f5e3 --- /dev/null +++ b/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme @@ -0,0 +1,125 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "0620" + version = "1.3"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "YES"> + <BuildActionEntries> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "YES" + buildForArchiving = "YES" + buildForAnalyzing = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "7461B52D0F94FAF800A0C422" + BuildableName = "libProtocolBuffers.a" + BlueprintName = "ProtocolBuffers" + ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj"> + </BuildableReference> + </BuildActionEntry> + </BuildActionEntries> + </BuildAction> + <TestAction + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + shouldUseLaunchSchemeArgsEnv = "YES" + buildConfiguration = "Release"> + <Testables> + <TestableReference + skipped = "NO"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "8BBEA4A5147C727100C4ADB7" + BuildableName = "UnitTests.xctest" + BlueprintName = "UnitTests" + ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj"> + </BuildableReference> + <SkippedTests> + <Test + Identifier = "ArrayTests"> + </Test> + <Test + Identifier = "CodedInputStreamTests"> + </Test> + <Test + Identifier = "CodedOutputStreamTests"> + </Test> + <Test + Identifier = "ConcurrencyTests"> + </Test> + <Test + Identifier = "FilteredMessageTests"> + </Test> + <Test + Identifier = "GPBStringTests"> + </Test> + <Test + Identifier = "GPBTestCase"> + </Test> + <Test + Identifier = "GeneratedMessageTests"> + </Test> + <Test + Identifier = "MessageTests"> + </Test> + <Test + Identifier = "UnknownFieldSetTest"> + </Test> + <Test + Identifier = "UtilitiesTests"> + </Test> + <Test + Identifier = "WireFormatTests"> + </Test> + </SkippedTests> + </TestableReference> + </Testables> + </TestAction> + <LaunchAction + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + buildConfiguration = "Release" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + allowLocationSimulation = "YES"> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "7461B52D0F94FAF800A0C422" + BuildableName = "libProtocolBuffers.a" + BlueprintName = "ProtocolBuffers" + ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj"> + </BuildableReference> + </MacroExpansion> + <AdditionalOptions> + </AdditionalOptions> + </LaunchAction> + <ProfileAction + shouldUseLaunchSchemeArgsEnv = "YES" + savedToolIdentifier = "" + useCustomWorkingDirectory = "NO" + buildConfiguration = "Release" + debugDocumentVersioning = "YES"> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "7461B52D0F94FAF800A0C422" + BuildableName = "libProtocolBuffers.a" + BlueprintName = "ProtocolBuffers" + ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj"> + </BuildableReference> + </MacroExpansion> + </ProfileAction> + <AnalyzeAction + buildConfiguration = "Release"> + </AnalyzeAction> + <ArchiveAction + buildConfiguration = "Release" + revealArchiveInOrganizer = "YES"> + </ArchiveAction> +</Scheme> diff --git a/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme b/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme new file mode 100644 index 00000000..f6f6e12b --- /dev/null +++ b/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme @@ -0,0 +1,115 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "0620" + version = "1.3"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "NO"> + <BuildActionEntries> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "YES" + buildForArchiving = "YES" + buildForAnalyzing = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "7461B52D0F94FAF800A0C422" + BuildableName = "libProtocolBuffers.a" + BlueprintName = "ProtocolBuffers" + ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj"> + </BuildableReference> + </BuildActionEntry> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "NO" + buildForArchiving = "NO" + buildForAnalyzing = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "F4487C381A9F8E0200531423" + BuildableName = "libTestSingleSourceBuild.a" + BlueprintName = "TestSingleSourceBuild" + ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj"> + </BuildableReference> + </BuildActionEntry> + </BuildActionEntries> + </BuildAction> + <TestAction + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + shouldUseLaunchSchemeArgsEnv = "YES" + buildConfiguration = "Debug"> + <Testables> + <TestableReference + skipped = "NO"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "8BBEA4A5147C727100C4ADB7" + BuildableName = "UnitTests.xctest" + BlueprintName = "UnitTests" + ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj"> + </BuildableReference> + <SkippedTests> + <Test + Identifier = "PerfTests"> + </Test> + </SkippedTests> + </TestableReference> + </Testables> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "7461B52D0F94FAF800A0C422" + BuildableName = "libProtocolBuffers.a" + BlueprintName = "ProtocolBuffers" + ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj"> + </BuildableReference> + </MacroExpansion> + </TestAction> + <LaunchAction + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + buildConfiguration = "Debug" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + allowLocationSimulation = "YES"> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "7461B52D0F94FAF800A0C422" + BuildableName = "libProtocolBuffers.a" + BlueprintName = "ProtocolBuffers" + ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj"> + </BuildableReference> + </MacroExpansion> + <AdditionalOptions> + </AdditionalOptions> + </LaunchAction> + <ProfileAction + shouldUseLaunchSchemeArgsEnv = "YES" + savedToolIdentifier = "" + useCustomWorkingDirectory = "NO" + buildConfiguration = "Release" + debugDocumentVersioning = "YES"> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "7461B52D0F94FAF800A0C422" + BuildableName = "libProtocolBuffers.a" + BlueprintName = "ProtocolBuffers" + ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj"> + </BuildableReference> + </MacroExpansion> + </ProfileAction> + <AnalyzeAction + buildConfiguration = "Debug"> + </AnalyzeAction> + <ArchiveAction + buildConfiguration = "Release" + revealArchiveInOrganizer = "YES"> + </ArchiveAction> +</Scheme> diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj new file mode 100644 index 00000000..7cf41359 --- /dev/null +++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj @@ -0,0 +1,1093 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 47; + objects = { + +/* Begin PBXAggregateTarget section */ + 8BD3981414BE4AE70081D629 /* Compile_Protos */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 8BD3981714BE4AE70081D629 /* Build configuration list for PBXAggregateTarget "Compile_Protos" */; + buildPhases = ( + 8BD3981814BE4AF30081D629 /* ShellScript */, + ); + dependencies = ( + ); + name = Compile_Protos; + productName = Compile_Protos; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 2CFB390415C718CE00CBF84D /* Descriptor.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */; }; + 5102DABC1891A073002037B6 /* GPBConcurrencyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5102DABB1891A052002037B6 /* GPBConcurrencyTests.m */; }; + 7461B5360F94FB4600A0C422 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; + 7461B53C0F94FB4E00A0C422 /* GPBCodedInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B48F0F94F99000A0C422 /* GPBCodedInputStream.m */; }; + 7461B53D0F94FB4E00A0C422 /* GPBCodedOutputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4910F94F99000A0C422 /* GPBCodedOutputStream.m */; }; + 7461B5490F94FB4E00A0C422 /* GPBExtensionRegistry.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4A90F94F99000A0C422 /* GPBExtensionRegistry.m */; }; + 7461B54C0F94FB4E00A0C422 /* GPBField.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4AF0F94F99000A0C422 /* GPBField.m */; }; + 7461B5530F94FB4E00A0C422 /* GPBMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4BF0F94F99000A0C422 /* GPBMessage.m */; }; + 7461B5610F94FB4E00A0C422 /* GPBUnknownFieldSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4E20F94F99000A0C422 /* GPBUnknownFieldSet.m */; }; + 7461B5630F94FB4E00A0C422 /* GPBUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4E60F94F99000A0C422 /* GPBUtilities.m */; }; + 7461B5640F94FB4E00A0C422 /* GPBWireFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B4E80F94F99000A0C422 /* GPBWireFormat.m */; }; + 8B210CCE159383D60032D72D /* golden_message in Resources */ = {isa = PBXBuildFile; fileRef = 8B210CCD159383D60032D72D /* golden_message */; }; + 8B210CD0159386920032D72D /* golden_packed_fields_message in Resources */ = {isa = PBXBuildFile; fileRef = 8B210CCF159386920032D72D /* golden_packed_fields_message */; }; + 8B4248B41A8BD96E00BC1EC6 /* GPBSwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B4248B31A8BD96E00BC1EC6 /* GPBSwiftTests.swift */; }; + 8B4248E41A929C8900BC1EC6 /* GPBWellKnownTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B4248E21A929C8900BC1EC6 /* GPBWellKnownTypes.m */; }; + 8B4248E61A929C9900BC1EC6 /* GPBWellKnownTypesTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B4248E51A929C9900BC1EC6 /* GPBWellKnownTypesTest.m */; }; + 8B79657B14992E3F002FFBFC /* GPBRootObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B79657914992E3E002FFBFC /* GPBRootObject.m */; }; + 8B79657D14992E3F002FFBFC /* GPBRootObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B79657914992E3E002FFBFC /* GPBRootObject.m */; }; + 8B8B615D17DF7056002EE618 /* GPBARCUnittestProtos.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B8B615C17DF7056002EE618 /* GPBARCUnittestProtos.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; }; + 8B96157414C8C38C00A2AC0B /* GPBDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B96157314C8C38C00A2AC0B /* GPBDescriptor.m */; }; + 8B96157514CA019D00A2AC0B /* Descriptor.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */; }; + 8B9742331A89D19F00DCE92C /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8B9742321A89D19F00DCE92C /* LaunchScreen.xib */; }; + 8B9742431A8AAA7800DCE92C /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B9742421A8AAA7800DCE92C /* CoreGraphics.framework */; }; + 8B9A5EA61831993600A9D33B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; + 8B9A5EA81831993600A9D33B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B9A5E9F1831913D00A9D33B /* UIKit.framework */; }; + 8B9A5EAE1831993600A9D33B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8B9A5EAC1831993600A9D33B /* InfoPlist.strings */; }; + 8B9A5EB41831993600A9D33B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B9A5EB31831993600A9D33B /* AppDelegate.m */; }; + 8B9A5EB61831993600A9D33B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8B9A5EB51831993600A9D33B /* Images.xcassets */; }; + 8B9A5EEC18330A0F00A9D33B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B9A5E9F1831913D00A9D33B /* UIKit.framework */; }; + 8BA9364518DA5F4C0056FA2A /* GPBStringTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */; }; + 8BBEA4A9147C727D00C4ADB7 /* GPBCodedInputStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B69B0F94FDF800A0C422 /* GPBCodedInputStreamTests.m */; }; + 8BBEA4AA147C727D00C4ADB7 /* GPBCodedOuputStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B69D0F94FDF800A0C422 /* GPBCodedOuputStreamTests.m */; }; + 8BBEA4AC147C727D00C4ADB7 /* GPBMessageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6A30F94FDF800A0C422 /* GPBMessageTests.m */; }; + 8BBEA4B0147C727D00C4ADB7 /* GPBTestUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */; }; + 8BBEA4B6147C727D00C4ADB7 /* GPBUnknownFieldSetTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6B80F94FDF900A0C422 /* GPBUnknownFieldSetTest.m */; }; + 8BBEA4B7147C727D00C4ADB7 /* GPBUtilitiesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6BA0F94FDF900A0C422 /* GPBUtilitiesTests.m */; }; + 8BBEA4B8147C727D00C4ADB7 /* GPBWireFormatTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6BC0F94FDF900A0C422 /* GPBWireFormatTests.m */; }; + 8BBEA4BB147C729200C4ADB7 /* libProtocolBuffers.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7461B52E0F94FAF800A0C422 /* libProtocolBuffers.a */; }; + 8BCC29BF16FD09A000F29F4A /* GPBFilteredMessageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BCC29BE16FD09A000F29F4A /* GPBFilteredMessageTests.m */; }; + 8BD3981F14BE59D70081D629 /* GPBUnittestProtos.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */; }; + 8BF8193514A0DDA600A2C982 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; + F401DC351A8E5C6F00FCC765 /* GPBArrayTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F401DC341A8E5C6F00FCC765 /* GPBArrayTests.m */; }; + F41C175D1833D3310064ED4D /* GPBPerfTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F41C175C1833D3310064ED4D /* GPBPerfTests.m */; }; + F4353D1F1AB88243005A6198 /* GPBDescriptorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D1E1AB88243005A6198 /* GPBDescriptorTests.m */; }; + F4353D271ABB156F005A6198 /* GPBDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D251ABB156F005A6198 /* GPBDictionary.m */; }; + F4353D421AC06F31005A6198 /* GPBDictionaryTests+Bool.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D3B1AC06F31005A6198 /* GPBDictionaryTests+Bool.m */; }; + F4353D431AC06F31005A6198 /* GPBDictionaryTests+Int32.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D3C1AC06F31005A6198 /* GPBDictionaryTests+Int32.m */; }; + F4353D441AC06F31005A6198 /* GPBDictionaryTests+Int64.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D3D1AC06F31005A6198 /* GPBDictionaryTests+Int64.m */; }; + F4353D451AC06F31005A6198 /* GPBDictionaryTests+String.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D3E1AC06F31005A6198 /* GPBDictionaryTests+String.m */; }; + F4353D461AC06F31005A6198 /* GPBDictionaryTests+UInt32.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D3F1AC06F31005A6198 /* GPBDictionaryTests+UInt32.m */; }; + F4353D471AC06F31005A6198 /* GPBDictionaryTests+UInt64.m in Sources */ = {isa = PBXBuildFile; fileRef = F4353D401AC06F31005A6198 /* GPBDictionaryTests+UInt64.m */; }; + F43C88D0191D77FC009E917D /* text_format_unittest_data.txt in Resources */ = {isa = PBXBuildFile; fileRef = F43C88CF191D77FC009E917D /* text_format_unittest_data.txt */; }; + F4487C5B1A9F8F8100531423 /* Descriptor.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */; }; + F4487C6A1A9F8F8100531423 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; + F4487C6F1A9F8FFF00531423 /* GPBProtocolBuffers.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BCF338814ED799900BC5317 /* GPBProtocolBuffers.m */; }; + F4487C731A9F906200531423 /* GPBArray.m in Sources */ = {isa = PBXBuildFile; fileRef = F4487C711A9F906200531423 /* GPBArray.m */; }; + F4487C771AADF84900531423 /* GPBMessageTests+Runtime.m in Sources */ = {isa = PBXBuildFile; fileRef = F4487C761AADF84900531423 /* GPBMessageTests+Runtime.m */; }; + F4487C811AAF62FC00531423 /* GPBMessageTests+Serialization.m in Sources */ = {isa = PBXBuildFile; fileRef = F4487C801AAF62FC00531423 /* GPBMessageTests+Serialization.m */; }; + F4487C851AAF6AC500531423 /* GPBMessageTests+Merge.m in Sources */ = {isa = PBXBuildFile; fileRef = F4487C841AAF6AC500531423 /* GPBMessageTests+Merge.m */; }; + F45C69CC16DFD08D0081955B /* GPBExtensionField.m in Sources */ = {isa = PBXBuildFile; fileRef = F45C69CB16DFD08D0081955B /* GPBExtensionField.m */; }; + F45E57C91AE6DC98000B7D99 /* text_format_map_unittest_data.txt in Resources */ = {isa = PBXBuildFile; fileRef = F45E57C81AE6DC98000B7D99 /* text_format_map_unittest_data.txt */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 8B9A5ED01831994600A9D33B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8B9A5EA41831993600A9D33B; + remoteInfo = iOSTestHarness; + }; + 8BBEA4BC147C729A00C4ADB7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 7461B52D0F94FAF800A0C422; + remoteInfo = ProtocolBuffers; + }; + 8BD3982014BE59EB0081D629 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8BD3981414BE4AE70081D629; + remoteInfo = Compile_Protos; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 5102DABB1891A052002037B6 /* GPBConcurrencyTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GPBConcurrencyTests.m; sourceTree = "<group>"; }; + 51457B5F18D0B7AF00CCC606 /* GPBCodedInputStream_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBCodedInputStream_PackagePrivate.h; sourceTree = "<group>"; }; + 515B840C18B7DEE30031753B /* GPBDescriptor_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBDescriptor_PackagePrivate.h; sourceTree = "<group>"; }; + 5196A06918CE16B000B759E2 /* GPBMessage_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBMessage_PackagePrivate.h; sourceTree = "<group>"; }; + 7401C1A90F950347006D8281 /* UnitTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "UnitTests-Info.plist"; sourceTree = "<group>"; }; + 7461B48D0F94F99000A0C422 /* GPBBootstrap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBBootstrap.h; sourceTree = "<group>"; }; + 7461B48E0F94F99000A0C422 /* GPBCodedInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBCodedInputStream.h; sourceTree = "<group>"; }; + 7461B48F0F94F99000A0C422 /* GPBCodedInputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = GPBCodedInputStream.m; sourceTree = "<group>"; }; + 7461B4900F94F99000A0C422 /* GPBCodedOutputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBCodedOutputStream.h; sourceTree = "<group>"; }; + 7461B4910F94F99000A0C422 /* GPBCodedOutputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBCodedOutputStream.m; sourceTree = "<group>"; }; + 7461B4A80F94F99000A0C422 /* GPBExtensionRegistry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBExtensionRegistry.h; sourceTree = "<group>"; }; + 7461B4A90F94F99000A0C422 /* GPBExtensionRegistry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBExtensionRegistry.m; sourceTree = "<group>"; }; + 7461B4AE0F94F99000A0C422 /* GPBField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBField.h; sourceTree = "<group>"; }; + 7461B4AF0F94F99000A0C422 /* GPBField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBField.m; sourceTree = "<group>"; }; + 7461B4BE0F94F99000A0C422 /* GPBMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBMessage.h; sourceTree = "<group>"; }; + 7461B4BF0F94F99000A0C422 /* GPBMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBMessage.m; sourceTree = "<group>"; }; + 7461B4CD0F94F99000A0C422 /* GPBProtocolBuffers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBProtocolBuffers.h; sourceTree = "<group>"; }; + 7461B4E10F94F99000A0C422 /* GPBUnknownFieldSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBUnknownFieldSet.h; sourceTree = "<group>"; }; + 7461B4E20F94F99000A0C422 /* GPBUnknownFieldSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnknownFieldSet.m; sourceTree = "<group>"; }; + 7461B4E50F94F99000A0C422 /* GPBUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBUtilities.h; sourceTree = "<group>"; }; + 7461B4E60F94F99000A0C422 /* GPBUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUtilities.m; sourceTree = "<group>"; }; + 7461B4E70F94F99000A0C422 /* GPBWireFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBWireFormat.h; sourceTree = "<group>"; }; + 7461B4E80F94F99000A0C422 /* GPBWireFormat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBWireFormat.m; sourceTree = "<group>"; }; + 7461B52E0F94FAF800A0C422 /* libProtocolBuffers.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libProtocolBuffers.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 7461B69B0F94FDF800A0C422 /* GPBCodedInputStreamTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBCodedInputStreamTests.m; sourceTree = "<group>"; }; + 7461B69D0F94FDF800A0C422 /* GPBCodedOuputStreamTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBCodedOuputStreamTests.m; sourceTree = "<group>"; }; + 7461B6A30F94FDF800A0C422 /* GPBMessageTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBMessageTests.m; sourceTree = "<group>"; }; + 7461B6AB0F94FDF800A0C422 /* GPBTestUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBTestUtilities.h; sourceTree = "<group>"; }; + 7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBTestUtilities.m; sourceTree = "<group>"; }; + 7461B6B80F94FDF900A0C422 /* GPBUnknownFieldSetTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnknownFieldSetTest.m; sourceTree = "<group>"; }; + 7461B6BA0F94FDF900A0C422 /* GPBUtilitiesTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUtilitiesTests.m; sourceTree = "<group>"; }; + 7461B6BC0F94FDF900A0C422 /* GPBWireFormatTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBWireFormatTests.m; sourceTree = "<group>"; }; + 748F0CAF0FD70602000858A9 /* GPBExtensionField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBExtensionField.h; sourceTree = "<group>"; }; + 8B09AAF614B663A7007B4184 /* unittest_objc.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_objc.proto; sourceTree = "<group>"; }; + 8B20A9A816F1BBFA00BE3EAD /* Filter1.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = Filter1.txt; sourceTree = "<group>"; }; + 8B20A9A916F1BC0600BE3EAD /* unittest_filter.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_filter.proto; sourceTree = "<group>"; }; + 8B210CCD159383D60032D72D /* golden_message */ = {isa = PBXFileReference; lastKnownFileType = file; path = golden_message; sourceTree = "<group>"; }; + 8B210CCF159386920032D72D /* golden_packed_fields_message */ = {isa = PBXFileReference; lastKnownFileType = file; path = golden_packed_fields_message; sourceTree = "<group>"; }; + 8B4248B21A8BD96D00BC1EC6 /* UnitTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UnitTests-Bridging-Header.h"; sourceTree = "<group>"; }; + 8B4248B31A8BD96E00BC1EC6 /* GPBSwiftTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GPBSwiftTests.swift; sourceTree = "<group>"; }; + 8B4248B71A8BDD9600BC1EC6 /* protobuf */ = {isa = PBXFileReference; lastKnownFileType = text; name = protobuf; path = ../../Intermediates/ProtocolBuffers_iOS.build/DerivedSources/protos/google/protobuf; sourceTree = BUILT_PRODUCTS_DIR; }; + 8B4248DD1A929C7D00BC1EC6 /* Duration.pbobjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Duration.pbobjc.h; path = google/protobuf/Duration.pbobjc.h; sourceTree = "<group>"; }; + 8B4248DE1A929C7D00BC1EC6 /* Duration.pbobjc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = Duration.pbobjc.m; path = google/protobuf/Duration.pbobjc.m; sourceTree = "<group>"; }; + 8B4248DF1A929C7D00BC1EC6 /* Timestamp.pbobjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Timestamp.pbobjc.h; path = /google/protobuf/Timestamp.pbobjc.h; sourceTree = "<group>"; }; + 8B4248E01A929C7D00BC1EC6 /* Timestamp.pbobjc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = Timestamp.pbobjc.m; path = google/protobuf/Timestamp.pbobjc.m; sourceTree = "<group>"; }; + 8B4248E11A929C8900BC1EC6 /* GPBWellKnownTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBWellKnownTypes.h; sourceTree = "<group>"; }; + 8B4248E21A929C8900BC1EC6 /* GPBWellKnownTypes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBWellKnownTypes.m; sourceTree = "<group>"; }; + 8B4248E51A929C9900BC1EC6 /* GPBWellKnownTypesTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBWellKnownTypesTest.m; sourceTree = "<group>"; }; + 8B4249481A92A02300BC1EC6 /* timestamp.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = timestamp.proto; path = ../src/google/protobuf/timestamp.proto; sourceTree = "<group>"; }; + 8B4249491A92A0BA00BC1EC6 /* descriptor.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = descriptor.proto; path = ../src/google/protobuf/descriptor.proto; sourceTree = "<group>"; }; + 8B42494A1A92A0BA00BC1EC6 /* duration.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = duration.proto; path = ../src/google/protobuf/duration.proto; sourceTree = "<group>"; }; + 8B54585814DCC34E003D7338 /* Descriptor.pbobjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Descriptor.pbobjc.h; path = /google/protobuf/Descriptor.pbobjc.h; sourceTree = SOURCE_ROOT; }; + 8B79657814992E3E002FFBFC /* GPBRootObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBRootObject.h; sourceTree = "<group>"; }; + 8B79657914992E3E002FFBFC /* GPBRootObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBRootObject.m; sourceTree = "<group>"; }; + 8B7E6A7414893DBA00F8884A /* unittest_custom_options.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_custom_options.proto; path = ../../src/google/protobuf/unittest_custom_options.proto; sourceTree = "<group>"; }; + 8B7E6A7514893DBA00F8884A /* unittest_embed_optimize_for.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_embed_optimize_for.proto; path = ../../src/google/protobuf/unittest_embed_optimize_for.proto; sourceTree = "<group>"; }; + 8B7E6A7614893DBA00F8884A /* unittest_empty.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_empty.proto; path = ../../src/google/protobuf/unittest_empty.proto; sourceTree = "<group>"; }; + 8B7E6A7814893DBB00F8884A /* unittest_import.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_import.proto; path = ../../src/google/protobuf/unittest_import.proto; sourceTree = "<group>"; }; + 8B7E6A7B14893DBC00F8884A /* unittest_mset.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_mset.proto; path = ../../src/google/protobuf/unittest_mset.proto; sourceTree = "<group>"; }; + 8B7E6A7C14893DBC00F8884A /* unittest_no_generic_services.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_no_generic_services.proto; path = ../../src/google/protobuf/unittest_no_generic_services.proto; sourceTree = "<group>"; }; + 8B7E6A7D14893DBC00F8884A /* unittest_optimize_for.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_optimize_for.proto; path = ../../src/google/protobuf/unittest_optimize_for.proto; sourceTree = "<group>"; }; + 8B7E6A7E14893DBC00F8884A /* unittest.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest.proto; path = ../../src/google/protobuf/unittest.proto; sourceTree = "<group>"; }; + 8B8B615C17DF7056002EE618 /* GPBARCUnittestProtos.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBARCUnittestProtos.m; sourceTree = "<group>"; }; + 8B96157214C8B06000A2AC0B /* GPBDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBDescriptor.h; sourceTree = "<group>"; }; + 8B96157314C8C38C00A2AC0B /* GPBDescriptor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBDescriptor.m; sourceTree = "<group>"; }; + 8B9742321A89D19F00DCE92C /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = "<group>"; }; + 8B9742421A8AAA7800DCE92C /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 8B9A5E9F1831913D00A9D33B /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 8B9A5EA51831993600A9D33B /* iOSTestHarness.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iOSTestHarness.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 8B9A5EAB1831993600A9D33B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; + 8B9A5EAD1831993600A9D33B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; }; + 8B9A5EB31831993600A9D33B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; }; + 8B9A5EB51831993600A9D33B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; }; + 8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBStringTests.m; sourceTree = "<group>"; }; + 8BBD9DB016DD1DC8008E1EC1 /* unittest_lite.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_lite.proto; path = ../../src/google/protobuf/unittest_lite.proto; sourceTree = "<group>"; }; + 8BBEA4A6147C727100C4ADB7 /* UnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 8BCC29BE16FD09A000F29F4A /* GPBFilteredMessageTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBFilteredMessageTests.m; sourceTree = "<group>"; }; + 8BCF338814ED799900BC5317 /* GPBProtocolBuffers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GPBProtocolBuffers.m; sourceTree = "<group>"; }; + 8BD3981D14BE54220081D629 /* unittest_enormous_descriptor.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_enormous_descriptor.proto; path = ../../src/google/protobuf/unittest_enormous_descriptor.proto; sourceTree = "<group>"; }; + 8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnittestProtos.m; sourceTree = "<group>"; }; + 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Descriptor.pbobjc.m; path = google/protobuf/Descriptor.pbobjc.m; sourceTree = SOURCE_ROOT; }; + 8BEB5AE01498033E0078BF9D /* GPBTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBTypes.h; sourceTree = "<group>"; }; + F401DC341A8E5C6F00FCC765 /* GPBArrayTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBArrayTests.m; sourceTree = "<group>"; }; + F41C175C1833D3310064ED4D /* GPBPerfTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBPerfTests.m; sourceTree = "<group>"; }; + F4353D1E1AB88243005A6198 /* GPBDescriptorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBDescriptorTests.m; sourceTree = "<group>"; }; + F4353D241ABB156F005A6198 /* GPBDictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBDictionary.h; sourceTree = "<group>"; }; + F4353D251ABB156F005A6198 /* GPBDictionary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBDictionary.m; sourceTree = "<group>"; }; + F4353D3A1AC06F31005A6198 /* GPBDictionaryTests.pddm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = GPBDictionaryTests.pddm; sourceTree = "<group>"; }; + F4353D3B1AC06F31005A6198 /* GPBDictionaryTests+Bool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+Bool.m"; sourceTree = "<group>"; }; + F4353D3C1AC06F31005A6198 /* GPBDictionaryTests+Int32.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+Int32.m"; sourceTree = "<group>"; }; + F4353D3D1AC06F31005A6198 /* GPBDictionaryTests+Int64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+Int64.m"; sourceTree = "<group>"; }; + F4353D3E1AC06F31005A6198 /* GPBDictionaryTests+String.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+String.m"; sourceTree = "<group>"; }; + F4353D3F1AC06F31005A6198 /* GPBDictionaryTests+UInt32.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+UInt32.m"; sourceTree = "<group>"; }; + F4353D401AC06F31005A6198 /* GPBDictionaryTests+UInt64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBDictionaryTests+UInt64.m"; sourceTree = "<group>"; }; + F43725921AC9835D004DCAFB /* GPBDictionary_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBDictionary_PackagePrivate.h; sourceTree = "<group>"; }; + F43C88CF191D77FC009E917D /* text_format_unittest_data.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = text_format_unittest_data.txt; sourceTree = "<group>"; }; + F4411BE81AF1301700324B4A /* GPBArray_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBArray_PackagePrivate.h; sourceTree = "<group>"; }; + F4487C6E1A9F8F8100531423 /* libTestSingleSourceBuild.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libTestSingleSourceBuild.a; sourceTree = BUILT_PRODUCTS_DIR; }; + F4487C701A9F906200531423 /* GPBArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBArray.h; sourceTree = "<group>"; }; + F4487C711A9F906200531423 /* GPBArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBArray.m; sourceTree = "<group>"; }; + F4487C761AADF84900531423 /* GPBMessageTests+Runtime.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBMessageTests+Runtime.m"; sourceTree = "<group>"; }; + F4487C7A1AADFB5500531423 /* unittest_runtime_proto2.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_runtime_proto2.proto; sourceTree = "<group>"; }; + F4487C7B1AADFB5500531423 /* unittest_runtime_proto3.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_runtime_proto3.proto; sourceTree = "<group>"; }; + F4487C7D1AAE06C500531423 /* GPBUtilities_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBUtilities_PackagePrivate.h; sourceTree = "<group>"; }; + F4487C801AAF62FC00531423 /* GPBMessageTests+Serialization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBMessageTests+Serialization.m"; sourceTree = "<group>"; }; + F4487C841AAF6AC500531423 /* GPBMessageTests+Merge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GPBMessageTests+Merge.m"; sourceTree = "<group>"; }; + F44B25D81A729803005CCF68 /* Filter2.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = Filter2.txt; sourceTree = "<group>"; }; + F451D3F61A8AAEA600B8A22C /* GPBProtocolBuffers_RuntimeSupport.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBProtocolBuffers_RuntimeSupport.h; sourceTree = "<group>"; }; + F45C69CB16DFD08D0081955B /* GPBExtensionField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBExtensionField.m; sourceTree = "<group>"; }; + F45E57C81AE6DC98000B7D99 /* text_format_map_unittest_data.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = text_format_map_unittest_data.txt; sourceTree = "<group>"; }; + F4AC9E1C1A8BEB1000BD6E83 /* unittest_cycle.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_cycle.proto; sourceTree = "<group>"; }; + F4B6B8B01A9CC99500892426 /* GPBField_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBField_PackagePrivate.h; sourceTree = "<group>"; }; + F4B6B8B11A9CCBBB00892426 /* GPBUnknownFieldSet_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBUnknownFieldSet_PackagePrivate.h; sourceTree = "<group>"; }; + F4B6B8B31A9CD1C600892426 /* GPBExtensionField_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBExtensionField_PackagePrivate.h; sourceTree = "<group>"; }; + F4B6B8B41A9CD1C600892426 /* GPBExtensionRegistry_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBExtensionRegistry_PackagePrivate.h; sourceTree = "<group>"; }; + F4B6B8B51A9CD1C600892426 /* GPBRootObject_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBRootObject_PackagePrivate.h; sourceTree = "<group>"; }; + F4B6B8BA1A9D343B00892426 /* unittest_name_mangling.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_name_mangling.proto; sourceTree = "<group>"; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 7461B52C0F94FAF800A0C422 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 7461B5360F94FB4600A0C422 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8B9A5EA21831993600A9D33B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8B9742431A8AAA7800DCE92C /* CoreGraphics.framework in Frameworks */, + 8B9A5EA81831993600A9D33B /* UIKit.framework in Frameworks */, + 8B9A5EA61831993600A9D33B /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8BBEA4A3147C727100C4ADB7 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8BBEA4BB147C729200C4ADB7 /* libProtocolBuffers.a in Frameworks */, + 8B9A5EEC18330A0F00A9D33B /* UIKit.framework in Frameworks */, + 8BF8193514A0DDA600A2C982 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F4487C691A9F8F8100531423 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + F4487C6A1A9F8F8100531423 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 080E96DDFE201D6D7F000001 /* Core Source */ = { + isa = PBXGroup; + children = ( + 7461B4CD0F94F99000A0C422 /* GPBProtocolBuffers.h */, + F451D3F61A8AAEA600B8A22C /* GPBProtocolBuffers_RuntimeSupport.h */, + 8BCF338814ED799900BC5317 /* GPBProtocolBuffers.m */, + 7461B3C50F94F84100A0C422 /* Extensions */, + 7461B4850F94F96600A0C422 /* Fields */, + 7461B4860F94F96B00A0C422 /* IO */, + 7461B5150F94FA7300A0C422 /* Messages */, + 8BCF334414ED727300BC5317 /* Support */, + 29B97315FDCFA39411CA2CEA /* Generated */, + ); + name = "Core Source"; + sourceTree = "<group>"; + }; + 19C28FACFE9D520D11CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 7461B52E0F94FAF800A0C422 /* libProtocolBuffers.a */, + 8BBEA4A6147C727100C4ADB7 /* UnitTests.xctest */, + 8B9A5EA51831993600A9D33B /* iOSTestHarness.app */, + F4487C6E1A9F8F8100531423 /* libTestSingleSourceBuild.a */, + ); + name = Products; + sourceTree = "<group>"; + }; + 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { + isa = PBXGroup; + children = ( + 080E96DDFE201D6D7F000001 /* Core Source */, + 7461B6940F94FDDD00A0C422 /* Tests */, + 29B97323FDCFA39411CA2CEA /* Frameworks */, + 19C28FACFE9D520D11CA2CBB /* Products */, + ); + name = CustomTemplate; + sourceTree = "<group>"; + }; + 29B97315FDCFA39411CA2CEA /* Generated */ = { + isa = PBXGroup; + children = ( + 8B4249491A92A0BA00BC1EC6 /* descriptor.proto */, + 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */, + 8B54585814DCC34E003D7338 /* Descriptor.pbobjc.h */, + 8B42494A1A92A0BA00BC1EC6 /* duration.proto */, + 8B4248DD1A929C7D00BC1EC6 /* Duration.pbobjc.h */, + 8B4248DE1A929C7D00BC1EC6 /* Duration.pbobjc.m */, + 8B4249481A92A02300BC1EC6 /* timestamp.proto */, + 8B4248DF1A929C7D00BC1EC6 /* Timestamp.pbobjc.h */, + 8B4248E01A929C7D00BC1EC6 /* Timestamp.pbobjc.m */, + ); + name = Generated; + sourceTree = "<group>"; + }; + 29B97323FDCFA39411CA2CEA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 8B9742421A8AAA7800DCE92C /* CoreGraphics.framework */, + 8B9A5E9F1831913D00A9D33B /* UIKit.framework */, + 1D30AB110D05D00D00671497 /* Foundation.framework */, + ); + name = Frameworks; + sourceTree = "<group>"; + }; + 7461B3C50F94F84100A0C422 /* Extensions */ = { + isa = PBXGroup; + children = ( + F4B6B8B31A9CD1C600892426 /* GPBExtensionField_PackagePrivate.h */, + 748F0CAF0FD70602000858A9 /* GPBExtensionField.h */, + F45C69CB16DFD08D0081955B /* GPBExtensionField.m */, + F4B6B8B41A9CD1C600892426 /* GPBExtensionRegistry_PackagePrivate.h */, + 7461B4A80F94F99000A0C422 /* GPBExtensionRegistry.h */, + 7461B4A90F94F99000A0C422 /* GPBExtensionRegistry.m */, + F4B6B8B51A9CD1C600892426 /* GPBRootObject_PackagePrivate.h */, + 8B79657814992E3E002FFBFC /* GPBRootObject.h */, + 8B79657914992E3E002FFBFC /* GPBRootObject.m */, + ); + name = Extensions; + sourceTree = "<group>"; + }; + 7461B4850F94F96600A0C422 /* Fields */ = { + isa = PBXGroup; + children = ( + F4B6B8B01A9CC99500892426 /* GPBField_PackagePrivate.h */, + 7461B4AE0F94F99000A0C422 /* GPBField.h */, + 7461B4AF0F94F99000A0C422 /* GPBField.m */, + F4B6B8B11A9CCBBB00892426 /* GPBUnknownFieldSet_PackagePrivate.h */, + 7461B4E10F94F99000A0C422 /* GPBUnknownFieldSet.h */, + 7461B4E20F94F99000A0C422 /* GPBUnknownFieldSet.m */, + ); + name = Fields; + sourceTree = "<group>"; + }; + 7461B4860F94F96B00A0C422 /* IO */ = { + isa = PBXGroup; + children = ( + 7461B48E0F94F99000A0C422 /* GPBCodedInputStream.h */, + 51457B5F18D0B7AF00CCC606 /* GPBCodedInputStream_PackagePrivate.h */, + 7461B48F0F94F99000A0C422 /* GPBCodedInputStream.m */, + 7461B4900F94F99000A0C422 /* GPBCodedOutputStream.h */, + 7461B4910F94F99000A0C422 /* GPBCodedOutputStream.m */, + 7461B4E70F94F99000A0C422 /* GPBWireFormat.h */, + 7461B4E80F94F99000A0C422 /* GPBWireFormat.m */, + ); + name = IO; + sourceTree = "<group>"; + }; + 7461B5150F94FA7300A0C422 /* Messages */ = { + isa = PBXGroup; + children = ( + 515B840C18B7DEE30031753B /* GPBDescriptor_PackagePrivate.h */, + 8B96157214C8B06000A2AC0B /* GPBDescriptor.h */, + 8B96157314C8C38C00A2AC0B /* GPBDescriptor.m */, + 7461B4BE0F94F99000A0C422 /* GPBMessage.h */, + 5196A06918CE16B000B759E2 /* GPBMessage_PackagePrivate.h */, + 7461B4BF0F94F99000A0C422 /* GPBMessage.m */, + ); + name = Messages; + sourceTree = "<group>"; + }; + 7461B6940F94FDDD00A0C422 /* Tests */ = { + isa = PBXGroup; + children = ( + 8B9A5EA91831993600A9D33B /* iOSTestHarness */, + 8B4248B71A8BDD9600BC1EC6 /* protobuf */, + 8B20A9A816F1BBFA00BE3EAD /* Filter1.txt */, + F44B25D81A729803005CCF68 /* Filter2.txt */, + 8B210CCD159383D60032D72D /* golden_message */, + 8B210CCF159386920032D72D /* golden_packed_fields_message */, + 8B8B615C17DF7056002EE618 /* GPBARCUnittestProtos.m */, + F401DC341A8E5C6F00FCC765 /* GPBArrayTests.m */, + 7461B69B0F94FDF800A0C422 /* GPBCodedInputStreamTests.m */, + 7461B69D0F94FDF800A0C422 /* GPBCodedOuputStreamTests.m */, + 5102DABB1891A052002037B6 /* GPBConcurrencyTests.m */, + F4353D1E1AB88243005A6198 /* GPBDescriptorTests.m */, + F4353D3A1AC06F31005A6198 /* GPBDictionaryTests.pddm */, + F4353D3B1AC06F31005A6198 /* GPBDictionaryTests+Bool.m */, + F4353D3C1AC06F31005A6198 /* GPBDictionaryTests+Int32.m */, + F4353D3D1AC06F31005A6198 /* GPBDictionaryTests+Int64.m */, + F4353D3E1AC06F31005A6198 /* GPBDictionaryTests+String.m */, + F4353D3F1AC06F31005A6198 /* GPBDictionaryTests+UInt32.m */, + F4353D401AC06F31005A6198 /* GPBDictionaryTests+UInt64.m */, + 8BCC29BE16FD09A000F29F4A /* GPBFilteredMessageTests.m */, + 7461B6A30F94FDF800A0C422 /* GPBMessageTests.m */, + F4487C841AAF6AC500531423 /* GPBMessageTests+Merge.m */, + F4487C761AADF84900531423 /* GPBMessageTests+Runtime.m */, + F4487C801AAF62FC00531423 /* GPBMessageTests+Serialization.m */, + F41C175C1833D3310064ED4D /* GPBPerfTests.m */, + 8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */, + 8B4248B31A8BD96E00BC1EC6 /* GPBSwiftTests.swift */, + 7461B6AB0F94FDF800A0C422 /* GPBTestUtilities.h */, + 7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */, + 8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */, + 7461B6B80F94FDF900A0C422 /* GPBUnknownFieldSetTest.m */, + 7461B6BA0F94FDF900A0C422 /* GPBUtilitiesTests.m */, + 8B4248E51A929C9900BC1EC6 /* GPBWellKnownTypesTest.m */, + 7461B6BC0F94FDF900A0C422 /* GPBWireFormatTests.m */, + F43C88CF191D77FC009E917D /* text_format_unittest_data.txt */, + F45E57C81AE6DC98000B7D99 /* text_format_map_unittest_data.txt */, + 8B7E6A7414893DBA00F8884A /* unittest_custom_options.proto */, + F4AC9E1C1A8BEB1000BD6E83 /* unittest_cycle.proto */, + 8B7E6A7514893DBA00F8884A /* unittest_embed_optimize_for.proto */, + 8B7E6A7614893DBA00F8884A /* unittest_empty.proto */, + 8BD3981D14BE54220081D629 /* unittest_enormous_descriptor.proto */, + 8B20A9A916F1BC0600BE3EAD /* unittest_filter.proto */, + 8B7E6A7814893DBB00F8884A /* unittest_import.proto */, + 8BBD9DB016DD1DC8008E1EC1 /* unittest_lite.proto */, + 8B7E6A7B14893DBC00F8884A /* unittest_mset.proto */, + F4B6B8BA1A9D343B00892426 /* unittest_name_mangling.proto */, + 8B7E6A7C14893DBC00F8884A /* unittest_no_generic_services.proto */, + 8B09AAF614B663A7007B4184 /* unittest_objc.proto */, + 8B7E6A7D14893DBC00F8884A /* unittest_optimize_for.proto */, + F4487C7A1AADFB5500531423 /* unittest_runtime_proto2.proto */, + F4487C7B1AADFB5500531423 /* unittest_runtime_proto3.proto */, + 8B7E6A7E14893DBC00F8884A /* unittest.proto */, + 8B4248B21A8BD96D00BC1EC6 /* UnitTests-Bridging-Header.h */, + 7401C1A90F950347006D8281 /* UnitTests-Info.plist */, + ); + path = Tests; + sourceTree = "<group>"; + }; + 8B9A5EA91831993600A9D33B /* iOSTestHarness */ = { + isa = PBXGroup; + children = ( + 8B9A5EB31831993600A9D33B /* AppDelegate.m */, + 8B9A5EB51831993600A9D33B /* Images.xcassets */, + 8B9A5EAA1831993600A9D33B /* Supporting Files */, + 8B9742321A89D19F00DCE92C /* LaunchScreen.xib */, + ); + path = iOSTestHarness; + sourceTree = "<group>"; + }; + 8B9A5EAA1831993600A9D33B /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 8B9A5EAB1831993600A9D33B /* Info.plist */, + 8B9A5EAC1831993600A9D33B /* InfoPlist.strings */, + ); + name = "Supporting Files"; + sourceTree = "<group>"; + }; + 8BCF334414ED727300BC5317 /* Support */ = { + isa = PBXGroup; + children = ( + F4411BE81AF1301700324B4A /* GPBArray_PackagePrivate.h */, + F4487C701A9F906200531423 /* GPBArray.h */, + F4487C711A9F906200531423 /* GPBArray.m */, + 7461B48D0F94F99000A0C422 /* GPBBootstrap.h */, + F43725921AC9835D004DCAFB /* GPBDictionary_PackagePrivate.h */, + F4353D241ABB156F005A6198 /* GPBDictionary.h */, + F4353D251ABB156F005A6198 /* GPBDictionary.m */, + 8BEB5AE01498033E0078BF9D /* GPBTypes.h */, + F4487C7D1AAE06C500531423 /* GPBUtilities_PackagePrivate.h */, + 7461B4E50F94F99000A0C422 /* GPBUtilities.h */, + 7461B4E60F94F99000A0C422 /* GPBUtilities.m */, + 8B4248E11A929C8900BC1EC6 /* GPBWellKnownTypes.h */, + 8B4248E21A929C8900BC1EC6 /* GPBWellKnownTypes.m */, + ); + name = Support; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 7461B52A0F94FAF800A0C422 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F4487C561A9F8F8100531423 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 7461B52D0F94FAF800A0C422 /* ProtocolBuffers */ = { + isa = PBXNativeTarget; + buildConfigurationList = 7461B5330F94FAFD00A0C422 /* Build configuration list for PBXNativeTarget "ProtocolBuffers" */; + buildPhases = ( + 7461B52A0F94FAF800A0C422 /* Headers */, + 7461B52B0F94FAF800A0C422 /* Sources */, + 7461B52C0F94FAF800A0C422 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ProtocolBuffers; + productName = "ProtocolBuffers-iPhoneDevice"; + productReference = 7461B52E0F94FAF800A0C422 /* libProtocolBuffers.a */; + productType = "com.apple.product-type.library.static"; + }; + 8B9A5EA41831993600A9D33B /* iOSTestHarness */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8B9A5ECA1831993600A9D33B /* Build configuration list for PBXNativeTarget "iOSTestHarness" */; + buildPhases = ( + 8B9A5EA11831993600A9D33B /* Sources */, + 8B9A5EA21831993600A9D33B /* Frameworks */, + 8B9A5EA31831993600A9D33B /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = iOSTestHarness; + productName = iOSTestHarness; + productReference = 8B9A5EA51831993600A9D33B /* iOSTestHarness.app */; + productType = "com.apple.product-type.application"; + }; + 8BBEA4A5147C727100C4ADB7 /* UnitTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8BBEA4BA147C728600C4ADB7 /* Build configuration list for PBXNativeTarget "UnitTests" */; + buildPhases = ( + F4B62A791AF91F7500AFCEDC /* Script: Check Runtime Stamps */, + 8BBEA4A1147C727100C4ADB7 /* Resources */, + 8BBEA4A2147C727100C4ADB7 /* Sources */, + 8BBEA4A3147C727100C4ADB7 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 8BBEA4BD147C729A00C4ADB7 /* PBXTargetDependency */, + 8BD3982114BE59EB0081D629 /* PBXTargetDependency */, + 8B9A5ED11831994600A9D33B /* PBXTargetDependency */, + ); + name = UnitTests; + productName = UnitTests; + productReference = 8BBEA4A6147C727100C4ADB7 /* UnitTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + F4487C551A9F8F8100531423 /* TestSingleSourceBuild */ = { + isa = PBXNativeTarget; + buildConfigurationList = F4487C6B1A9F8F8100531423 /* Build configuration list for PBXNativeTarget "TestSingleSourceBuild" */; + buildPhases = ( + F4487C561A9F8F8100531423 /* Headers */, + F4487C5A1A9F8F8100531423 /* Sources */, + F4487C691A9F8F8100531423 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = TestSingleSourceBuild; + productName = "ProtocolBuffers-iPhoneDevice"; + productReference = F4487C6E1A9F8F8100531423 /* libTestSingleSourceBuild.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 29B97313FDCFA39411CA2CEA /* Project object */ = { + isa = PBXProject; + attributes = { + LastTestingUpgradeCheck = 0600; + LastUpgradeCheck = 0610; + TargetAttributes = { + 8BBEA4A5147C727100C4ADB7 = { + TestTargetID = 8B9A5EA41831993600A9D33B; + }; + }; + }; + buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "ProtocolBuffers_iOS" */; + compatibilityVersion = "Xcode 6.3"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + en, + ); + mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 7461B52D0F94FAF800A0C422 /* ProtocolBuffers */, + 8BBEA4A5147C727100C4ADB7 /* UnitTests */, + 8BD3981414BE4AE70081D629 /* Compile_Protos */, + 8B9A5EA41831993600A9D33B /* iOSTestHarness */, + F4487C551A9F8F8100531423 /* TestSingleSourceBuild */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8B9A5EA31831993600A9D33B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8B9A5EAE1831993600A9D33B /* InfoPlist.strings in Resources */, + 8B9A5EB61831993600A9D33B /* Images.xcassets in Resources */, + 8B9742331A89D19F00DCE92C /* LaunchScreen.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8BBEA4A1147C727100C4ADB7 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8B210CCE159383D60032D72D /* golden_message in Resources */, + F43C88D0191D77FC009E917D /* text_format_unittest_data.txt in Resources */, + 8B210CD0159386920032D72D /* golden_packed_fields_message in Resources */, + F45E57C91AE6DC98000B7D99 /* text_format_map_unittest_data.txt in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 8BD3981814BE4AF30081D629 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/../src/google/protobuf/unittest_custom_options.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_embed_optimize_for.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_empty.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_enormous_descriptor.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_import_lite.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_import.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_lite_imports_nonlite.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_lite.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_mset.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_no_generic_services.proto", + "$(SRCROOT)/../src/google/protobuf/unittest.proto", + "$(SRCROOT)/Tests/unittest_objc.proto", + "$(SRCROOT)/../src/.libs/libprotoc.10.dylib", + "$(SRCROOT)/../src/google/protobuf/unittest_import_public_lite.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_import_public.proto", + "$(SRCROOT)/Tests/unittest_filter.proto", + "$(SRCROOT)/../src/.libs/libprotobuf.10.dylib", + "$(SRCROOT)/../src/.libs/protoc", + "$(SRCROOT)/Tests/Filter1.txt", + "$(SRCROOT)/Tests/Filter2.txt", + "$(SRCROOT)/Tests/unittest_cycle.proto", + "$(SRCROOT)/Tests/unittest_name_mangling.proto", + "$(SRCROOT)/Tests/unittest_runtime_proto2.proto", + "$(SRCROOT)/Tests/unittest_runtime_proto3.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_drop_unknown_fields.proto", + "$(SRCROOT)/../src/google/protobuf/unittest_preserve_unknown_enum.proto", + "$(SRCROOT)/../src/google/protobuf/map_lite_unittest.proto", + "$(SRCROOT)/../src/google/protobuf/map_proto2_unittest.proto", + "$(SRCROOT)/../src/google/protobuf/map_unittest.proto", + ); + outputPaths = ( + "$(PROJECT_DERIVED_FILE_DIR)/protos/google/protobuf/Unittest.pbobjc.h", + "$(PROJECT_DERIVED_FILE_DIR)/protos/google/protobuf/Unittest.pbobjc.m", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/bash; + shellScript = "set -eu\nmkdir -p \"${PROJECT_DERIVED_FILE_DIR}/protos\"\nexport PATH=\"${PATH}:.\"\ncd \"${SRCROOT}\"/../src\n\nPROTOC=./protoc\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_custom_options.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_enormous_descriptor.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_embed_optimize_for.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_empty.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import_lite.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_lite.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_mset.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_no_generic_services.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_optimize_for.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import_public.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import_public_lite.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_drop_unknown_fields.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_preserve_unknown_enum.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/map_lite_unittest.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/map_proto2_unittest.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/map_unittest.proto\n\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_objc.proto\n\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_cycle.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_name_mangling.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_runtime_proto2.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_runtime_proto3.proto\n\nexport GPB_CLASSLIST_PATH=\"${PROJECT_DERIVED_FILE_DIR}/ClassList.txt\"\nexport GPB_OBJC_CLASS_WHITELIST_PATHS=\"${SRCROOT}/Tests/Filter1.txt;${SRCROOT}/Tests/Filter2.txt\"\n\nif [ -e ${GPB_CLASSLIST_PATH} ]; then\nrm ${GPB_CLASSLIST_PATH}\nfi\n\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_filter.proto\n\n"; + showEnvVarsInLog = 0; + }; + F4B62A791AF91F7500AFCEDC /* Script: Check Runtime Stamps */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Script: Check Runtime Stamps"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "set -eu\nexec \"${SOURCE_ROOT}/DevTools/check_version_stamps.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 7461B52B0F94FAF800A0C422 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2CFB390415C718CE00CBF84D /* Descriptor.pbobjc.m in Sources */, + 7461B53C0F94FB4E00A0C422 /* GPBCodedInputStream.m in Sources */, + F4487C731A9F906200531423 /* GPBArray.m in Sources */, + 7461B53D0F94FB4E00A0C422 /* GPBCodedOutputStream.m in Sources */, + 7461B5490F94FB4E00A0C422 /* GPBExtensionRegistry.m in Sources */, + 7461B54C0F94FB4E00A0C422 /* GPBField.m in Sources */, + 7461B5530F94FB4E00A0C422 /* GPBMessage.m in Sources */, + 7461B5610F94FB4E00A0C422 /* GPBUnknownFieldSet.m in Sources */, + 7461B5630F94FB4E00A0C422 /* GPBUtilities.m in Sources */, + 7461B5640F94FB4E00A0C422 /* GPBWireFormat.m in Sources */, + F4353D271ABB156F005A6198 /* GPBDictionary.m in Sources */, + 8B79657B14992E3F002FFBFC /* GPBRootObject.m in Sources */, + 8B96157414C8C38C00A2AC0B /* GPBDescriptor.m in Sources */, + F45C69CC16DFD08D0081955B /* GPBExtensionField.m in Sources */, + 8B4248E41A929C8900BC1EC6 /* GPBWellKnownTypes.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8B9A5EA11831993600A9D33B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8B9A5EB41831993600A9D33B /* AppDelegate.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8BBEA4A2147C727100C4ADB7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8BBEA4A9147C727D00C4ADB7 /* GPBCodedInputStreamTests.m in Sources */, + F401DC351A8E5C6F00FCC765 /* GPBArrayTests.m in Sources */, + F4353D441AC06F31005A6198 /* GPBDictionaryTests+Int64.m in Sources */, + F4353D471AC06F31005A6198 /* GPBDictionaryTests+UInt64.m in Sources */, + 8BBEA4AA147C727D00C4ADB7 /* GPBCodedOuputStreamTests.m in Sources */, + 8BBEA4AC147C727D00C4ADB7 /* GPBMessageTests.m in Sources */, + F4487C811AAF62FC00531423 /* GPBMessageTests+Serialization.m in Sources */, + 8B4248E61A929C9900BC1EC6 /* GPBWellKnownTypesTest.m in Sources */, + F4353D1F1AB88243005A6198 /* GPBDescriptorTests.m in Sources */, + 8B4248B41A8BD96E00BC1EC6 /* GPBSwiftTests.swift in Sources */, + 5102DABC1891A073002037B6 /* GPBConcurrencyTests.m in Sources */, + F4487C771AADF84900531423 /* GPBMessageTests+Runtime.m in Sources */, + F4353D431AC06F31005A6198 /* GPBDictionaryTests+Int32.m in Sources */, + 8BBEA4B0147C727D00C4ADB7 /* GPBTestUtilities.m in Sources */, + F41C175D1833D3310064ED4D /* GPBPerfTests.m in Sources */, + F4353D421AC06F31005A6198 /* GPBDictionaryTests+Bool.m in Sources */, + F4487C851AAF6AC500531423 /* GPBMessageTests+Merge.m in Sources */, + 8BA9364518DA5F4C0056FA2A /* GPBStringTests.m in Sources */, + 8BBEA4B6147C727D00C4ADB7 /* GPBUnknownFieldSetTest.m in Sources */, + F4353D451AC06F31005A6198 /* GPBDictionaryTests+String.m in Sources */, + F4353D461AC06F31005A6198 /* GPBDictionaryTests+UInt32.m in Sources */, + 8BBEA4B7147C727D00C4ADB7 /* GPBUtilitiesTests.m in Sources */, + 8BBEA4B8147C727D00C4ADB7 /* GPBWireFormatTests.m in Sources */, + 8B79657D14992E3F002FFBFC /* GPBRootObject.m in Sources */, + 8BD3981F14BE59D70081D629 /* GPBUnittestProtos.m in Sources */, + 8B96157514CA019D00A2AC0B /* Descriptor.pbobjc.m in Sources */, + 8BCC29BF16FD09A000F29F4A /* GPBFilteredMessageTests.m in Sources */, + 8B8B615D17DF7056002EE618 /* GPBARCUnittestProtos.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F4487C5A1A9F8F8100531423 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F4487C5B1A9F8F8100531423 /* Descriptor.pbobjc.m in Sources */, + F4487C6F1A9F8FFF00531423 /* GPBProtocolBuffers.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 8B9A5ED11831994600A9D33B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 8B9A5EA41831993600A9D33B /* iOSTestHarness */; + targetProxy = 8B9A5ED01831994600A9D33B /* PBXContainerItemProxy */; + }; + 8BBEA4BD147C729A00C4ADB7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 7461B52D0F94FAF800A0C422 /* ProtocolBuffers */; + targetProxy = 8BBEA4BC147C729A00C4ADB7 /* PBXContainerItemProxy */; + }; + 8BD3982114BE59EB0081D629 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 8BD3981414BE4AE70081D629 /* Compile_Protos */; + targetProxy = 8BD3982014BE59EB0081D629 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 8B9A5EAC1831993600A9D33B /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 8B9A5EAD1831993600A9D33B /* en */, + ); + name = InfoPlist.strings; + sourceTree = "<group>"; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 7461B52F0F94FAFA00A0C422 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = "$(SRCROOT)"; + PRODUCT_NAME = ProtocolBuffers; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 7461B5300F94FAFA00A0C422 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = "$(SRCROOT)"; + PRODUCT_NAME = ProtocolBuffers; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 8B9A5ECB1831993600A9D33B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CLANG_ENABLE_OBJC_ARC = YES; + INFOPLIST_FILE = "$(SRCROOT)/Tests/iOSTestHarness/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 7.1; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 8B9A5ECC1831993600A9D33B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CLANG_ENABLE_OBJC_ARC = YES; + INFOPLIST_FILE = "$(SRCROOT)/Tests/iOSTestHarness/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 7.1; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; + 8BBEA4A7147C727100C4ADB7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + FRAMEWORK_SEARCH_PATHS = ( + "\"$(SDKROOT)/Developer/Library/Frameworks\"", + "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", + "$(inherited)", + ); + HEADER_SEARCH_PATHS = ( + "${PROJECT_DERIVED_FILE_DIR}/protos", + "$(SRCROOT)", + ); + INFOPLIST_FILE = "Tests/UnitTests-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 7.1; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(DEVELOPER_DIR)/usr/lib\"", + ); + PRODUCT_NAME = UnitTests; + SWIFT_OBJC_BRIDGING_HEADER = "Tests/UnitTests-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iOSTestHarness.app/iOSTestHarness"; + }; + name = Debug; + }; + 8BBEA4A8147C727100C4ADB7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + FRAMEWORK_SEARCH_PATHS = ( + "\"$(SDKROOT)/Developer/Library/Frameworks\"", + "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", + "$(inherited)", + ); + HEADER_SEARCH_PATHS = ( + "${PROJECT_DERIVED_FILE_DIR}/protos", + "$(SRCROOT)", + ); + INFOPLIST_FILE = "Tests/UnitTests-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 7.1; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(DEVELOPER_DIR)/usr/lib\"", + ); + PRODUCT_NAME = UnitTests; + SWIFT_OBJC_BRIDGING_HEADER = "Tests/UnitTests-Bridging-Header.h"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iOSTestHarness.app/iOSTestHarness"; + }; + name = Release; + }; + 8BD3981514BE4AE70081D629 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 8BD3981614BE4AE70081D629 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + C01FCF4F08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = YES; + CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES; + CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES; + CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES; + CLANG_STATIC_ANALYZER_MODE = deep; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; + CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES; + CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1"; + GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; + GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_MISSING_PARENTHESES = YES; + GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; + GCC_WARN_SHADOW = YES; + GCC_WARN_SIGN_COMPARE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_PARAMETER = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + GENERATE_PROFILING_CODE = NO; + IPHONEOS_DEPLOYMENT_TARGET = 6.1; + ONLY_ACTIVE_ARCH = YES; + RUN_CLANG_STATIC_ANALYZER = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + C01FCF5008A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = YES; + CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES; + CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES; + CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES; + CLANG_STATIC_ANALYZER_MODE = deep; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; + CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES; + CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; + GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_MISSING_PARENTHESES = YES; + GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; + GCC_WARN_SHADOW = YES; + GCC_WARN_SIGN_COMPARE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_PARAMETER = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + GENERATE_PROFILING_CODE = NO; + IPHONEOS_DEPLOYMENT_TARGET = 6.1; + RUN_CLANG_STATIC_ANALYZER = YES; + SDKROOT = iphoneos; + }; + name = Release; + }; + F4487C6C1A9F8F8100531423 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = "$(SRCROOT)"; + PRODUCT_NAME = TestSingleSourceBuild; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + F4487C6D1A9F8F8100531423 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = "$(SRCROOT)"; + PRODUCT_NAME = TestSingleSourceBuild; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 7461B5330F94FAFD00A0C422 /* Build configuration list for PBXNativeTarget "ProtocolBuffers" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7461B52F0F94FAFA00A0C422 /* Debug */, + 7461B5300F94FAFA00A0C422 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8B9A5ECA1831993600A9D33B /* Build configuration list for PBXNativeTarget "iOSTestHarness" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8B9A5ECB1831993600A9D33B /* Debug */, + 8B9A5ECC1831993600A9D33B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8BBEA4BA147C728600C4ADB7 /* Build configuration list for PBXNativeTarget "UnitTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8BBEA4A7147C727100C4ADB7 /* Debug */, + 8BBEA4A8147C727100C4ADB7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8BD3981714BE4AE70081D629 /* Build configuration list for PBXAggregateTarget "Compile_Protos" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8BD3981514BE4AE70081D629 /* Debug */, + 8BD3981614BE4AE70081D629 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C01FCF4E08A954540054247B /* Build configuration list for PBXProject "ProtocolBuffers_iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4F08A954540054247B /* Debug */, + C01FCF5008A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F4487C6B1A9F8F8100531423 /* Build configuration list for PBXNativeTarget "TestSingleSourceBuild" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F4487C6C1A9F8F8100531423 /* Debug */, + F4487C6D1A9F8F8100531423 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; +} diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..037a91df --- /dev/null +++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Workspace + version = "1.0"> + <FileRef + location = "self:ProtocolBuffers_iOS.xcodeproj"> + </FileRef> +</Workspace> diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..08de0be8 --- /dev/null +++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key> + <false/> +</dict> +</plist> diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcbaselines/8BBEA4A5147C727100C4ADB7.xcbaseline/FFE465CA-0E74-40E8-9F09-500B66B7DCB2.plist b/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcbaselines/8BBEA4A5147C727100C4ADB7.xcbaseline/FFE465CA-0E74-40E8-9F09-500B66B7DCB2.plist new file mode 100644 index 00000000..0ac0943a --- /dev/null +++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcbaselines/8BBEA4A5147C727100C4ADB7.xcbaseline/FFE465CA-0E74-40E8-9F09-500B66B7DCB2.plist @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>classNames</key> + <dict> + <key>PerfTests</key> + <dict> + <key>testExtensionsPerformance</key> + <dict> + <key>com.apple.XCTPerformanceMetric_WallClockTime</key> + <dict> + <key>baselineAverage</key> + <real>0.9</real> + <key>baselineIntegrationDisplayName</key> + <string>Feb 5, 2015, 9:42:41 AM</string> + </dict> + </dict> + <key>testHas</key> + <dict> + <key>com.apple.XCTPerformanceMetric_WallClockTime</key> + <dict> + <key>baselineAverage</key> + <real>0.09</real> + <key>baselineIntegrationDisplayName</key> + <string>Feb 5, 2015, 9:42:35 AM</string> + </dict> + </dict> + <key>testMessagePerformance</key> + <dict> + <key>com.apple.XCTPerformanceMetric_WallClockTime</key> + <dict> + <key>baselineAverage</key> + <real>0.57</real> + <key>baselineIntegrationDisplayName</key> + <string>Feb 5, 2015, 9:42:47 AM</string> + </dict> + </dict> + <key>testPackedExtensionsPerformance</key> + <dict> + <key>com.apple.XCTPerformanceMetric_WallClockTime</key> + <dict> + <key>baselineAverage</key> + <real>0.75</real> + <key>baselineIntegrationDisplayName</key> + <string>Feb 5, 2015, 9:42:51 AM</string> + </dict> + </dict> + <key>testPackedTypesPerformance</key> + <dict> + <key>com.apple.XCTPerformanceMetric_WallClockTime</key> + <dict> + <key>baselineAverage</key> + <real>0.26</real> + <key>baselineIntegrationDisplayName</key> + <string>Feb 5, 2015, 9:42:55 AM</string> + </dict> + </dict> + </dict> + </dict> +</dict> +</plist> diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcbaselines/8BBEA4A5147C727100C4ADB7.xcbaseline/Info.plist b/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcbaselines/8BBEA4A5147C727100C4ADB7.xcbaseline/Info.plist new file mode 100644 index 00000000..45bb9c1b --- /dev/null +++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcbaselines/8BBEA4A5147C727100C4ADB7.xcbaseline/Info.plist @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>runDestinationsByUUID</key> + <dict> + <key>FFE465CA-0E74-40E8-9F09-500B66B7DCB2</key> + <dict> + <key>targetArchitecture</key> + <string>arm64</string> + <key>targetDevice</key> + <dict> + <key>modelCode</key> + <string>iPhone7,1</string> + <key>platformIdentifier</key> + <string>com.apple.platform.iphoneos</string> + </dict> + </dict> + </dict> +</dict> +</plist> diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme b/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme new file mode 100644 index 00000000..f5479ba2 --- /dev/null +++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme @@ -0,0 +1,134 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "0610" + version = "1.3"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "YES"> + <BuildActionEntries> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "YES" + buildForArchiving = "YES" + buildForAnalyzing = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "7461B52D0F94FAF800A0C422" + BuildableName = "libProtocolBuffers.a" + BlueprintName = "ProtocolBuffers" + ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj"> + </BuildableReference> + </BuildActionEntry> + </BuildActionEntries> + </BuildAction> + <TestAction + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + shouldUseLaunchSchemeArgsEnv = "YES" + buildConfiguration = "Release"> + <Testables> + <TestableReference + skipped = "NO"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "8BBEA4A5147C727100C4ADB7" + BuildableName = "UnitTests.xctest" + BlueprintName = "UnitTests" + ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj"> + </BuildableReference> + <SkippedTests> + <Test + Identifier = "ArrayTests"> + </Test> + <Test + Identifier = "CodedInputStreamTests"> + </Test> + <Test + Identifier = "CodedOutputStreamTests"> + </Test> + <Test + Identifier = "ConcurrencyTests"> + </Test> + <Test + Identifier = "FilteredMessageTests"> + </Test> + <Test + Identifier = "GPBStringTests"> + </Test> + <Test + Identifier = "GPBTestCase"> + </Test> + <Test + Identifier = "GeneratedMessageTests"> + </Test> + <Test + Identifier = "MessageTests"> + </Test> + <Test + Identifier = "UnknownFieldSetTest"> + </Test> + <Test + Identifier = "UtilitiesTests"> + </Test> + <Test + Identifier = "WireFormatTests"> + </Test> + </SkippedTests> + </TestableReference> + </Testables> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "8B9A5EA41831993600A9D33B" + BuildableName = "iOSTestHarness.app" + BlueprintName = "iOSTestHarness" + ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj"> + </BuildableReference> + </MacroExpansion> + </TestAction> + <LaunchAction + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + buildConfiguration = "Release" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + allowLocationSimulation = "YES"> + <BuildableProductRunnable> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "8B9A5EA41831993600A9D33B" + BuildableName = "iOSTestHarness.app" + BlueprintName = "iOSTestHarness" + ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj"> + </BuildableReference> + </BuildableProductRunnable> + <AdditionalOptions> + </AdditionalOptions> + </LaunchAction> + <ProfileAction + shouldUseLaunchSchemeArgsEnv = "YES" + savedToolIdentifier = "" + useCustomWorkingDirectory = "NO" + buildConfiguration = "Release" + debugDocumentVersioning = "YES"> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "7461B52D0F94FAF800A0C422" + BuildableName = "libProtocolBuffers.a" + BlueprintName = "ProtocolBuffers" + ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj"> + </BuildableReference> + </MacroExpansion> + </ProfileAction> + <AnalyzeAction + buildConfiguration = "Release"> + </AnalyzeAction> + <ArchiveAction + buildConfiguration = "Release" + revealArchiveInOrganizer = "YES"> + </ArchiveAction> +</Scheme> diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme b/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme new file mode 100644 index 00000000..a1b4cc45 --- /dev/null +++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme @@ -0,0 +1,116 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "0610" + version = "1.3"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "NO"> + <BuildActionEntries> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "YES" + buildForArchiving = "YES" + buildForAnalyzing = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "7461B52D0F94FAF800A0C422" + BuildableName = "libProtocolBuffers.a" + BlueprintName = "ProtocolBuffers" + ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj"> + </BuildableReference> + </BuildActionEntry> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "NO" + buildForArchiving = "NO" + buildForAnalyzing = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "F4487C551A9F8F8100531423" + BuildableName = "libTestSingleSourceBuild.a" + BlueprintName = "TestSingleSourceBuild" + ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj"> + </BuildableReference> + </BuildActionEntry> + </BuildActionEntries> + </BuildAction> + <TestAction + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + shouldUseLaunchSchemeArgsEnv = "YES" + buildConfiguration = "Debug"> + <Testables> + <TestableReference + skipped = "NO"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "8BBEA4A5147C727100C4ADB7" + BuildableName = "UnitTests.xctest" + BlueprintName = "UnitTests" + ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj"> + </BuildableReference> + <SkippedTests> + <Test + Identifier = "PerfTests"> + </Test> + </SkippedTests> + </TestableReference> + </Testables> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "8B9A5EA41831993600A9D33B" + BuildableName = "iOSTestHarness.app" + BlueprintName = "iOSTestHarness" + ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj"> + </BuildableReference> + </MacroExpansion> + </TestAction> + <LaunchAction + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + buildConfiguration = "Debug" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + allowLocationSimulation = "YES"> + <BuildableProductRunnable + runnableDebuggingMode = "0"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "8B9A5EA41831993600A9D33B" + BuildableName = "iOSTestHarness.app" + BlueprintName = "iOSTestHarness" + ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj"> + </BuildableReference> + </BuildableProductRunnable> + <AdditionalOptions> + </AdditionalOptions> + </LaunchAction> + <ProfileAction + shouldUseLaunchSchemeArgsEnv = "YES" + savedToolIdentifier = "" + useCustomWorkingDirectory = "NO" + buildConfiguration = "Release" + debugDocumentVersioning = "YES"> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "7461B52D0F94FAF800A0C422" + BuildableName = "libProtocolBuffers.a" + BlueprintName = "ProtocolBuffers" + ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj"> + </BuildableReference> + </MacroExpansion> + </ProfileAction> + <AnalyzeAction + buildConfiguration = "Debug"> + </AnalyzeAction> + <ArchiveAction + buildConfiguration = "Release" + revealArchiveInOrganizer = "YES"> + </ArchiveAction> +</Scheme> diff --git a/objectivec/Tests/Filter1.txt b/objectivec/Tests/Filter1.txt new file mode 100644 index 00000000..88a5cac8 --- /dev/null +++ b/objectivec/Tests/Filter1.txt @@ -0,0 +1,40 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 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. + + +// Test the filter system for the ObjC Protocol Buffer Compiler. + +// Class names are matched using file name globbing rules. +// Whitespace is not allowed at the beginning of a line (except for a line +// that is a single newline). + +Keep +RemoveEnumMessage_KeepNestedInside +RemoveJustKidding diff --git a/objectivec/Tests/Filter2.txt b/objectivec/Tests/Filter2.txt new file mode 100644 index 00000000..5a2bb0f8 --- /dev/null +++ b/objectivec/Tests/Filter2.txt @@ -0,0 +1,35 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 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. + + +// Test the filter system for the ObjC Protocol Buffer Compiler to test +// multiple filter support. + +Other diff --git a/objectivec/Tests/GPBARCUnittestProtos.m b/objectivec/Tests/GPBARCUnittestProtos.m new file mode 100644 index 00000000..daf4effc --- /dev/null +++ b/objectivec/Tests/GPBARCUnittestProtos.m @@ -0,0 +1,57 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +// 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. + +// Makes sure all the generated headers compile with ARC on. + +#import "google/protobuf/Unittest.pbobjc.h" +#import "google/protobuf/UnittestCustomOptions.pbobjc.h" +#import "google/protobuf/UnittestCycle.pbobjc.h" +#import "google/protobuf/UnittestDropUnknownFields.pbobjc.h" +#import "google/protobuf/UnittestEmbedOptimizeFor.pbobjc.h" +#import "google/protobuf/UnittestEmpty.pbobjc.h" +#import "google/protobuf/UnittestEnormousDescriptor.pbobjc.h" +#import "google/protobuf/UnittestFilter.pbobjc.h" +#import "google/protobuf/UnittestImport.pbobjc.h" +#import "google/protobuf/UnittestImportLite.pbobjc.h" +#import "google/protobuf/UnittestImportPublic.pbobjc.h" +#import "google/protobuf/UnittestImportPublicLite.pbobjc.h" +#import "google/protobuf/UnittestLite.pbobjc.h" +#import "google/protobuf/UnittestMset.pbobjc.h" +#import "google/protobuf/UnittestNameMangling.pbobjc.h" +#import "google/protobuf/UnittestNoGenericServices.pbobjc.h" +#import "google/protobuf/UnittestObjc.pbobjc.h" +#import "google/protobuf/UnittestOptimizeFor.pbobjc.h" +#import "google/protobuf/UnittestPreserveUnknownEnum.pbobjc.h" +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h" +#import "google/protobuf/UnittestRuntimeProto3.pbobjc.h" diff --git a/objectivec/Tests/GPBArrayTests.m b/objectivec/Tests/GPBArrayTests.m new file mode 100644 index 00000000..37724c59 --- /dev/null +++ b/objectivec/Tests/GPBArrayTests.m @@ -0,0 +1,3365 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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. + +#import <Foundation/Foundation.h> + +#import <XCTest/XCTest.h> + +#import "GPBArray.h" + +#ifndef GPBARRAYSIZE +#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0])))) +#endif // GPBARRAYSIZE + +// To let the testing macros work, add some extra methods to simplify things. +@interface GPBEnumArray (TestingTweak) ++ (instancetype)arrayWithValue:(int32_t)value; +- (instancetype)initWithValues:(const int32_t [])values + count:(NSUInteger)count; +@end + +static BOOL TestingEnum_IsValidValue(int32_t value) { + switch (value) { + case 71: + case 72: + case 73: + case 74: + return YES; + default: + return NO; + } +} + +static BOOL TestingEnum_IsValidValue2(int32_t value) { + switch (value) { + case 71: + case 72: + case 73: + return YES; + default: + return NO; + } +} + +@implementation GPBEnumArray (TestingTweak) ++ (instancetype)arrayWithValue:(int32_t)value { + return [[[self alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:&value + count:1] autorelease]; +} +- (instancetype)initWithValues:(const int32_t [])values + count:(NSUInteger)count { + return [self initWithValidationFunction:TestingEnum_IsValidValue + rawValues:values + count:count]; +} +@end + +#pragma mark - PDDM Macros + +//%PDDM-DEFINE ARRAY_TESTS(NAME, TYPE, VAL1, VAL2, VAL3, VAL4) +//%ARRAY_TESTS2(NAME, TYPE, VAL1, VAL2, VAL3, VAL4, ) +//%PDDM-DEFINE ARRAY_TESTS2(NAME, TYPE, VAL1, VAL2, VAL3, VAL4, HELPER) +//%#pragma mark - NAME +//% +//%@interface GPB##NAME##ArrayTests : XCTestCase +//%@end +//% +//%@implementation GPB##NAME##ArrayTests +//% +//%- (void)testEmpty { +//% GPB##NAME##Array *array = [[GPB##NAME##Array alloc] init]; +//% XCTAssertNotNil(array); +//% XCTAssertEqual(array.count, 0U); +//% XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException); +//% [array enumerateValuesWithBlock:^(TYPE value, NSUInteger idx, BOOL *stop) { +//% #pragma unused(value, idx, stop) +//% XCTFail(@"Shouldn't get here!"); +//% }]; +//% [array enumerateValuesWithOptions:NSEnumerationReverse +//% usingBlock:^(TYPE value, NSUInteger idx, BOOL *stop) { +//% #pragma unused(value, idx, stop) +//% XCTFail(@"Shouldn't get here!"); +//% }]; +//% [array release]; +//%} +//% +//%- (void)testOne { +//% GPB##NAME##Array *array = [GPB##NAME##Array arrayWithValue:VAL1]; +//% XCTAssertNotNil(array); +//% XCTAssertEqual(array.count, 1U); +//% XCTAssertEqual([array valueAtIndex:0], VAL1); +//% XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException); +//% [array enumerateValuesWithBlock:^(TYPE value, NSUInteger idx, BOOL *stop) { +//% XCTAssertEqual(idx, 0U); +//% XCTAssertEqual(value, VAL1); +//% XCTAssertNotEqual(stop, NULL); +//% }]; +//% [array enumerateValuesWithOptions:NSEnumerationReverse +//% usingBlock:^(TYPE value, NSUInteger idx, BOOL *stop) { +//% XCTAssertEqual(idx, 0U); +//% XCTAssertEqual(value, VAL1); +//% XCTAssertNotEqual(stop, NULL); +//% }]; +//%} +//% +//%- (void)testBasics { +//% static const TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; +//% GPB##NAME##Array *array = +//% [[GPB##NAME##Array alloc] initWithValues:kValues +//% NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(array); +//% XCTAssertEqual(array.count, 4U); +//% XCTAssertEqual([array valueAtIndex:0], VAL1); +//% XCTAssertEqual([array valueAtIndex:1], VAL2); +//% XCTAssertEqual([array valueAtIndex:2], VAL3); +//% XCTAssertEqual([array valueAtIndex:3], VAL4); +//% XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException); +//% __block NSUInteger idx2 = 0; +//% [array enumerateValuesWithBlock:^(TYPE value, NSUInteger idx, BOOL *stop) { +//% XCTAssertEqual(idx, idx2); +//% XCTAssertEqual(value, kValues[idx]); +//% XCTAssertNotEqual(stop, NULL); +//% ++idx2; +//% }]; +//% idx2 = 0; +//% [array enumerateValuesWithOptions:NSEnumerationReverse +//% usingBlock:^(TYPE value, NSUInteger idx, BOOL *stop) { +//% XCTAssertEqual(idx, (3 - idx2)); +//% XCTAssertEqual(value, kValues[idx]); +//% XCTAssertNotEqual(stop, NULL); +//% ++idx2; +//% }]; +//% // Stopping the enumeration. +//% idx2 = 0; +//% [array enumerateValuesWithBlock:^(TYPE value, NSUInteger idx, BOOL *stop) { +//% XCTAssertEqual(idx, idx2); +//% XCTAssertEqual(value, kValues[idx]); +//% XCTAssertNotEqual(stop, NULL); +//% if (idx2 == 1) *stop = YES; +//% XCTAssertNotEqual(idx, 2U); +//% XCTAssertNotEqual(idx, 3U); +//% ++idx2; +//% }]; +//% idx2 = 0; +//% [array enumerateValuesWithOptions:NSEnumerationReverse +//% usingBlock:^(TYPE value, NSUInteger idx, BOOL *stop) { +//% XCTAssertEqual(idx, (3 - idx2)); +//% XCTAssertEqual(value, kValues[idx]); +//% XCTAssertNotEqual(stop, NULL); +//% if (idx2 == 1) *stop = YES; +//% XCTAssertNotEqual(idx, 1U); +//% XCTAssertNotEqual(idx, 0U); +//% ++idx2; +//% }]; +//% [array release]; +//%} +//% +//%- (void)testEquality { +//% const TYPE kValues1[] = { VAL1, VAL2, VAL3 }; +//% const TYPE kValues2[] = { VAL1, VAL4, VAL3 }; +//% const TYPE kValues3[] = { VAL1, VAL2, VAL3, VAL4 }; +//% GPB##NAME##Array *array1 = +//% [[GPB##NAME##Array alloc] initWithValues:kValues1 +//% NAME$S count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertNotNil(array1); +//% GPB##NAME##Array *array1prime = +//% [[GPB##NAME##Array alloc] initWithValues:kValues1 +//% NAME$S count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertNotNil(array1prime); +//% GPB##NAME##Array *array2 = +//% [[GPB##NAME##Array alloc] initWithValues:kValues2 +//% NAME$S count:GPBARRAYSIZE(kValues2)]; +//% XCTAssertNotNil(array2); +//% GPB##NAME##Array *array3 = +//% [[GPB##NAME##Array alloc] initWithValues:kValues3 +//% NAME$S count:GPBARRAYSIZE(kValues3)]; +//% XCTAssertNotNil(array3); +//% +//% // 1/1Prime should be different objects, but equal. +//% XCTAssertNotEqual(array1, array1prime); +//% XCTAssertEqualObjects(array1, array1prime); +//% // Equal, so they must have same hash. +//% XCTAssertEqual([array1 hash], [array1prime hash]); +//% +//% // 1/2/3 shouldn't be equal. +//% XCTAssertNotEqualObjects(array1, array2); +//% XCTAssertNotEqualObjects(array1, array3); +//% XCTAssertNotEqualObjects(array2, array3); +//% +//% [array1 release]; +//% [array1prime release]; +//% [array2 release]; +//% [array3 release]; +//%} +//% +//%- (void)testCopy { +//% const TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; +//% GPB##NAME##Array *array = +//% [[GPB##NAME##Array alloc] initWithValues:kValues +//% NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(array); +//% +//% GPB##NAME##Array *array2 = [array copy]; +//% XCTAssertNotNil(array2); +//% +//% // Should be new object but equal. +//% XCTAssertNotEqual(array, array2); +//% XCTAssertEqualObjects(array, array2); +//%} +//% +//%- (void)testArrayFromArray { +//% const TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; +//% GPB##NAME##Array *array = +//% [[GPB##NAME##Array alloc] initWithValues:kValues +//% NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(array); +//% +//% GPB##NAME##Array *array2 = [GPB##NAME##Array arrayWithValueArray:array]; +//% XCTAssertNotNil(array2); +//% +//% // Should be new pointer, but equal objects. +//% XCTAssertNotEqual(array, array2); +//% XCTAssertEqualObjects(array, array2); +//%} +//% +//%- (void)testAdds { +//% GPB##NAME##Array *array = [GPB##NAME##Array array]; +//% XCTAssertNotNil(array); +//% +//% XCTAssertEqual(array.count, 0U); +//% [array addValue:VAL1]; +//% XCTAssertEqual(array.count, 1U); +//% +//% const TYPE kValues1[] = { VAL2, VAL3 }; +//% [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertEqual(array.count, 3U); +//% +//% const TYPE kValues2[] = { VAL4, VAL1 }; +//% GPB##NAME##Array *array2 = +//% [[GPB##NAME##Array alloc] initWithValues:kValues2 +//% NAME$S count:GPBARRAYSIZE(kValues2)]; +//% XCTAssertNotNil(array2); +//% [array add##HELPER##ValuesFromArray:array2]; +//% XCTAssertEqual(array.count, 5U); +//% +//% XCTAssertEqual([array valueAtIndex:0], VAL1); +//% XCTAssertEqual([array valueAtIndex:1], VAL2); +//% XCTAssertEqual([array valueAtIndex:2], VAL3); +//% XCTAssertEqual([array valueAtIndex:3], VAL4); +//% XCTAssertEqual([array valueAtIndex:4], VAL1); +//%} +//% +//%- (void)testInsert { +//% const TYPE kValues[] = { VAL1, VAL2, VAL3 }; +//% GPB##NAME##Array *array = +//% [[GPB##NAME##Array alloc] initWithValues:kValues +//% NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(array); +//% XCTAssertEqual(array.count, 3U); +//% +//% // First +//% [array insertValue:VAL4 atIndex:0]; +//% XCTAssertEqual(array.count, 4U); +//% +//% // Middle +//% [array insertValue:VAL4 atIndex:2]; +//% XCTAssertEqual(array.count, 5U); +//% +//% // End +//% [array insertValue:VAL4 atIndex:5]; +//% XCTAssertEqual(array.count, 6U); +//% +//% // Too far. +//% XCTAssertThrowsSpecificNamed([array insertValue:VAL4 atIndex:7], +//% NSException, NSRangeException); +//% +//% XCTAssertEqual([array valueAtIndex:0], VAL4); +//% XCTAssertEqual([array valueAtIndex:1], VAL1); +//% XCTAssertEqual([array valueAtIndex:2], VAL4); +//% XCTAssertEqual([array valueAtIndex:3], VAL2); +//% XCTAssertEqual([array valueAtIndex:4], VAL3); +//% XCTAssertEqual([array valueAtIndex:5], VAL4); +//%} +//% +//%- (void)testRemove { +//% const TYPE kValues[] = { VAL4, VAL1, VAL2, VAL4, VAL3, VAL4 }; +//% GPB##NAME##Array *array = +//% [[GPB##NAME##Array alloc] initWithValues:kValues +//% NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(array); +//% XCTAssertEqual(array.count, 6U); +//% +//% // First +//% [array removeValueAtIndex:0]; +//% XCTAssertEqual(array.count, 5U); +//% XCTAssertEqual([array valueAtIndex:0], VAL1); +//% +//% // Middle +//% [array removeValueAtIndex:2]; +//% XCTAssertEqual(array.count, 4U); +//% XCTAssertEqual([array valueAtIndex:2], VAL3); +//% +//% // End +//% [array removeValueAtIndex:3]; +//% XCTAssertEqual(array.count, 3U); +//% +//% XCTAssertEqual([array valueAtIndex:0], VAL1); +//% XCTAssertEqual([array valueAtIndex:1], VAL2); +//% XCTAssertEqual([array valueAtIndex:2], VAL3); +//% +//% // Too far. +//% XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3], +//% NSException, NSRangeException); +//% +//% [array removeAll]; +//% XCTAssertEqual(array.count, 0U); +//% XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0], +//% NSException, NSRangeException); +//%} +//% +//%- (void)testInplaceMutation { +//% const TYPE kValues[] = { VAL1, VAL1, VAL3, VAL3 }; +//% GPB##NAME##Array *array = +//% [[GPB##NAME##Array alloc] initWithValues:kValues +//% NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(array); +//% +//% [array replaceValueAtIndex:1 withValue:VAL2]; +//% [array replaceValueAtIndex:3 withValue:VAL4]; +//% XCTAssertEqual(array.count, 4U); +//% XCTAssertEqual([array valueAtIndex:0], VAL1); +//% XCTAssertEqual([array valueAtIndex:1], VAL2); +//% XCTAssertEqual([array valueAtIndex:2], VAL3); +//% XCTAssertEqual([array valueAtIndex:3], VAL4); +//% +//% XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:VAL4], +//% NSException, NSRangeException); +//% +//% [array exchangeValueAtIndex:1 withValueAtIndex:3]; +//% XCTAssertEqual(array.count, 4U); +//% XCTAssertEqual([array valueAtIndex:0], VAL1); +//% XCTAssertEqual([array valueAtIndex:1], VAL4); +//% XCTAssertEqual([array valueAtIndex:2], VAL3); +//% XCTAssertEqual([array valueAtIndex:3], VAL2); +//% +//% [array exchangeValueAtIndex:2 withValueAtIndex:0]; +//% XCTAssertEqual(array.count, 4U); +//% XCTAssertEqual([array valueAtIndex:0], VAL3); +//% XCTAssertEqual([array valueAtIndex:1], VAL4); +//% XCTAssertEqual([array valueAtIndex:2], VAL1); +//% XCTAssertEqual([array valueAtIndex:3], VAL2); +//% +//% XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1], +//% NSException, NSRangeException); +//% XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4], +//% NSException, NSRangeException); +//%} +//% +//%- (void)testInternalResizing { +//% const TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; +//% GPB##NAME##Array *array = +//% [[GPB##NAME##Array alloc] initWithValues:kValues +//% NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(array); +//% +//% // Add/remove to trigger the intneral buffer to grow/shrink. +//% for (int i = 0; i < 100; ++i) { +//% [array addValues:kValues count:GPBARRAYSIZE(kValues)]; +//% } +//% XCTAssertEqual(array.count, 404U); +//% for (int i = 0; i < 100; ++i) { +//% [array removeValueAtIndex:(i * 2)]; +//% } +//% XCTAssertEqual(array.count, 304U); +//% for (int i = 0; i < 100; ++i) { +//% [array insertValue:VAL4 atIndex:(i * 3)]; +//% } +//% XCTAssertEqual(array.count, 404U); +//% [array removeAll]; +//% XCTAssertEqual(array.count, 0U); +//%} +//% +//%@end +//% +//%PDDM-EXPAND ARRAY_TESTS(Int32, int32_t, 1, 2, 3, 4) +// This block of code is generated, do not edit it directly. + +#pragma mark - Int32 + +@interface GPBInt32ArrayTests : XCTestCase +@end + +@implementation GPBInt32ArrayTests + +- (void)testEmpty { + GPBInt32Array *array = [[GPBInt32Array alloc] init]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array release]; +} + +- (void)testOne { + GPBInt32Array *array = [GPBInt32Array arrayWithValue:1]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 1U); + XCTAssertEqual([array valueAtIndex:0], 1); + XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 1); + XCTAssertNotEqual(stop, NULL); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 1); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + static const int32_t kValues[] = { 1, 2, 3, 4 }; + GPBInt32Array *array = + [[GPBInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 1); + XCTAssertEqual([array valueAtIndex:1], 2); + XCTAssertEqual([array valueAtIndex:2], 3); + XCTAssertEqual([array valueAtIndex:3], 4); + XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException); + __block NSUInteger idx2 = 0; + [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + // Stopping the enumeration. + idx2 = 0; + [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + XCTAssertNotEqual(idx, 3U); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 1U); + XCTAssertNotEqual(idx, 0U); + ++idx2; + }]; + [array release]; +} + +- (void)testEquality { + const int32_t kValues1[] = { 1, 2, 3 }; + const int32_t kValues2[] = { 1, 4, 3 }; + const int32_t kValues3[] = { 1, 2, 3, 4 }; + GPBInt32Array *array1 = + [[GPBInt32Array alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1); + GPBInt32Array *array1prime = + [[GPBInt32Array alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1prime); + GPBInt32Array *array2 = + [[GPBInt32Array alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + GPBInt32Array *array3 = + [[GPBInt32Array alloc] initWithValues:kValues3 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(array3); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(array1, array1prime); + XCTAssertEqualObjects(array1, array1prime); + // Equal, so they must have same hash. + XCTAssertEqual([array1 hash], [array1prime hash]); + + // 1/2/3 shouldn't be equal. + XCTAssertNotEqualObjects(array1, array2); + XCTAssertNotEqualObjects(array1, array3); + XCTAssertNotEqualObjects(array2, array3); + + [array1 release]; + [array1prime release]; + [array2 release]; + [array3 release]; +} + +- (void)testCopy { + const int32_t kValues[] = { 1, 2, 3, 4 }; + GPBInt32Array *array = + [[GPBInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBInt32Array *array2 = [array copy]; + XCTAssertNotNil(array2); + + // Should be new object but equal. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testArrayFromArray { + const int32_t kValues[] = { 1, 2, 3, 4 }; + GPBInt32Array *array = + [[GPBInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBInt32Array *array2 = [GPBInt32Array arrayWithValueArray:array]; + XCTAssertNotNil(array2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testAdds { + GPBInt32Array *array = [GPBInt32Array array]; + XCTAssertNotNil(array); + + XCTAssertEqual(array.count, 0U); + [array addValue:1]; + XCTAssertEqual(array.count, 1U); + + const int32_t kValues1[] = { 2, 3 }; + [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)]; + XCTAssertEqual(array.count, 3U); + + const int32_t kValues2[] = { 4, 1 }; + GPBInt32Array *array2 = + [[GPBInt32Array alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + [array addValuesFromArray:array2]; + XCTAssertEqual(array.count, 5U); + + XCTAssertEqual([array valueAtIndex:0], 1); + XCTAssertEqual([array valueAtIndex:1], 2); + XCTAssertEqual([array valueAtIndex:2], 3); + XCTAssertEqual([array valueAtIndex:3], 4); + XCTAssertEqual([array valueAtIndex:4], 1); +} + +- (void)testInsert { + const int32_t kValues[] = { 1, 2, 3 }; + GPBInt32Array *array = + [[GPBInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 3U); + + // First + [array insertValue:4 atIndex:0]; + XCTAssertEqual(array.count, 4U); + + // Middle + [array insertValue:4 atIndex:2]; + XCTAssertEqual(array.count, 5U); + + // End + [array insertValue:4 atIndex:5]; + XCTAssertEqual(array.count, 6U); + + // Too far. + XCTAssertThrowsSpecificNamed([array insertValue:4 atIndex:7], + NSException, NSRangeException); + + XCTAssertEqual([array valueAtIndex:0], 4); + XCTAssertEqual([array valueAtIndex:1], 1); + XCTAssertEqual([array valueAtIndex:2], 4); + XCTAssertEqual([array valueAtIndex:3], 2); + XCTAssertEqual([array valueAtIndex:4], 3); + XCTAssertEqual([array valueAtIndex:5], 4); +} + +- (void)testRemove { + const int32_t kValues[] = { 4, 1, 2, 4, 3, 4 }; + GPBInt32Array *array = + [[GPBInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 6U); + + // First + [array removeValueAtIndex:0]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], 1); + + // Middle + [array removeValueAtIndex:2]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:2], 3); + + // End + [array removeValueAtIndex:3]; + XCTAssertEqual(array.count, 3U); + + XCTAssertEqual([array valueAtIndex:0], 1); + XCTAssertEqual([array valueAtIndex:1], 2); + XCTAssertEqual([array valueAtIndex:2], 3); + + // Too far. + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3], + NSException, NSRangeException); + + [array removeAll]; + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0], + NSException, NSRangeException); +} + +- (void)testInplaceMutation { + const int32_t kValues[] = { 1, 1, 3, 3 }; + GPBInt32Array *array = + [[GPBInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + [array replaceValueAtIndex:1 withValue:2]; + [array replaceValueAtIndex:3 withValue:4]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 1); + XCTAssertEqual([array valueAtIndex:1], 2); + XCTAssertEqual([array valueAtIndex:2], 3); + XCTAssertEqual([array valueAtIndex:3], 4); + + XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:4], + NSException, NSRangeException); + + [array exchangeValueAtIndex:1 withValueAtIndex:3]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 1); + XCTAssertEqual([array valueAtIndex:1], 4); + XCTAssertEqual([array valueAtIndex:2], 3); + XCTAssertEqual([array valueAtIndex:3], 2); + + [array exchangeValueAtIndex:2 withValueAtIndex:0]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 3); + XCTAssertEqual([array valueAtIndex:1], 4); + XCTAssertEqual([array valueAtIndex:2], 1); + XCTAssertEqual([array valueAtIndex:3], 2); + + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1], + NSException, NSRangeException); + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4], + NSException, NSRangeException); +} + +- (void)testInternalResizing { + const int32_t kValues[] = { 1, 2, 3, 4 }; + GPBInt32Array *array = + [[GPBInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + // Add/remove to trigger the intneral buffer to grow/shrink. + for (int i = 0; i < 100; ++i) { + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; + } + XCTAssertEqual(array.count, 404U); + for (int i = 0; i < 100; ++i) { + [array removeValueAtIndex:(i * 2)]; + } + XCTAssertEqual(array.count, 304U); + for (int i = 0; i < 100; ++i) { + [array insertValue:4 atIndex:(i * 3)]; + } + XCTAssertEqual(array.count, 404U); + [array removeAll]; + XCTAssertEqual(array.count, 0U); +} + +@end + +//%PDDM-EXPAND ARRAY_TESTS(UInt32, uint32_t, 11U, 12U, 13U, 14U) +// This block of code is generated, do not edit it directly. + +#pragma mark - UInt32 + +@interface GPBUInt32ArrayTests : XCTestCase +@end + +@implementation GPBUInt32ArrayTests + +- (void)testEmpty { + GPBUInt32Array *array = [[GPBUInt32Array alloc] init]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array release]; +} + +- (void)testOne { + GPBUInt32Array *array = [GPBUInt32Array arrayWithValue:11U]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 1U); + XCTAssertEqual([array valueAtIndex:0], 11U); + XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 11U); + XCTAssertNotEqual(stop, NULL); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 11U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + static const uint32_t kValues[] = { 11U, 12U, 13U, 14U }; + GPBUInt32Array *array = + [[GPBUInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 11U); + XCTAssertEqual([array valueAtIndex:1], 12U); + XCTAssertEqual([array valueAtIndex:2], 13U); + XCTAssertEqual([array valueAtIndex:3], 14U); + XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException); + __block NSUInteger idx2 = 0; + [array enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + // Stopping the enumeration. + idx2 = 0; + [array enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + XCTAssertNotEqual(idx, 3U); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 1U); + XCTAssertNotEqual(idx, 0U); + ++idx2; + }]; + [array release]; +} + +- (void)testEquality { + const uint32_t kValues1[] = { 11U, 12U, 13U }; + const uint32_t kValues2[] = { 11U, 14U, 13U }; + const uint32_t kValues3[] = { 11U, 12U, 13U, 14U }; + GPBUInt32Array *array1 = + [[GPBUInt32Array alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1); + GPBUInt32Array *array1prime = + [[GPBUInt32Array alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1prime); + GPBUInt32Array *array2 = + [[GPBUInt32Array alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + GPBUInt32Array *array3 = + [[GPBUInt32Array alloc] initWithValues:kValues3 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(array3); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(array1, array1prime); + XCTAssertEqualObjects(array1, array1prime); + // Equal, so they must have same hash. + XCTAssertEqual([array1 hash], [array1prime hash]); + + // 1/2/3 shouldn't be equal. + XCTAssertNotEqualObjects(array1, array2); + XCTAssertNotEqualObjects(array1, array3); + XCTAssertNotEqualObjects(array2, array3); + + [array1 release]; + [array1prime release]; + [array2 release]; + [array3 release]; +} + +- (void)testCopy { + const uint32_t kValues[] = { 11U, 12U, 13U, 14U }; + GPBUInt32Array *array = + [[GPBUInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBUInt32Array *array2 = [array copy]; + XCTAssertNotNil(array2); + + // Should be new object but equal. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testArrayFromArray { + const uint32_t kValues[] = { 11U, 12U, 13U, 14U }; + GPBUInt32Array *array = + [[GPBUInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBUInt32Array *array2 = [GPBUInt32Array arrayWithValueArray:array]; + XCTAssertNotNil(array2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testAdds { + GPBUInt32Array *array = [GPBUInt32Array array]; + XCTAssertNotNil(array); + + XCTAssertEqual(array.count, 0U); + [array addValue:11U]; + XCTAssertEqual(array.count, 1U); + + const uint32_t kValues1[] = { 12U, 13U }; + [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)]; + XCTAssertEqual(array.count, 3U); + + const uint32_t kValues2[] = { 14U, 11U }; + GPBUInt32Array *array2 = + [[GPBUInt32Array alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + [array addValuesFromArray:array2]; + XCTAssertEqual(array.count, 5U); + + XCTAssertEqual([array valueAtIndex:0], 11U); + XCTAssertEqual([array valueAtIndex:1], 12U); + XCTAssertEqual([array valueAtIndex:2], 13U); + XCTAssertEqual([array valueAtIndex:3], 14U); + XCTAssertEqual([array valueAtIndex:4], 11U); +} + +- (void)testInsert { + const uint32_t kValues[] = { 11U, 12U, 13U }; + GPBUInt32Array *array = + [[GPBUInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 3U); + + // First + [array insertValue:14U atIndex:0]; + XCTAssertEqual(array.count, 4U); + + // Middle + [array insertValue:14U atIndex:2]; + XCTAssertEqual(array.count, 5U); + + // End + [array insertValue:14U atIndex:5]; + XCTAssertEqual(array.count, 6U); + + // Too far. + XCTAssertThrowsSpecificNamed([array insertValue:14U atIndex:7], + NSException, NSRangeException); + + XCTAssertEqual([array valueAtIndex:0], 14U); + XCTAssertEqual([array valueAtIndex:1], 11U); + XCTAssertEqual([array valueAtIndex:2], 14U); + XCTAssertEqual([array valueAtIndex:3], 12U); + XCTAssertEqual([array valueAtIndex:4], 13U); + XCTAssertEqual([array valueAtIndex:5], 14U); +} + +- (void)testRemove { + const uint32_t kValues[] = { 14U, 11U, 12U, 14U, 13U, 14U }; + GPBUInt32Array *array = + [[GPBUInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 6U); + + // First + [array removeValueAtIndex:0]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], 11U); + + // Middle + [array removeValueAtIndex:2]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:2], 13U); + + // End + [array removeValueAtIndex:3]; + XCTAssertEqual(array.count, 3U); + + XCTAssertEqual([array valueAtIndex:0], 11U); + XCTAssertEqual([array valueAtIndex:1], 12U); + XCTAssertEqual([array valueAtIndex:2], 13U); + + // Too far. + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3], + NSException, NSRangeException); + + [array removeAll]; + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0], + NSException, NSRangeException); +} + +- (void)testInplaceMutation { + const uint32_t kValues[] = { 11U, 11U, 13U, 13U }; + GPBUInt32Array *array = + [[GPBUInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + [array replaceValueAtIndex:1 withValue:12U]; + [array replaceValueAtIndex:3 withValue:14U]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 11U); + XCTAssertEqual([array valueAtIndex:1], 12U); + XCTAssertEqual([array valueAtIndex:2], 13U); + XCTAssertEqual([array valueAtIndex:3], 14U); + + XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:14U], + NSException, NSRangeException); + + [array exchangeValueAtIndex:1 withValueAtIndex:3]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 11U); + XCTAssertEqual([array valueAtIndex:1], 14U); + XCTAssertEqual([array valueAtIndex:2], 13U); + XCTAssertEqual([array valueAtIndex:3], 12U); + + [array exchangeValueAtIndex:2 withValueAtIndex:0]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 13U); + XCTAssertEqual([array valueAtIndex:1], 14U); + XCTAssertEqual([array valueAtIndex:2], 11U); + XCTAssertEqual([array valueAtIndex:3], 12U); + + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1], + NSException, NSRangeException); + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4], + NSException, NSRangeException); +} + +- (void)testInternalResizing { + const uint32_t kValues[] = { 11U, 12U, 13U, 14U }; + GPBUInt32Array *array = + [[GPBUInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + // Add/remove to trigger the intneral buffer to grow/shrink. + for (int i = 0; i < 100; ++i) { + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; + } + XCTAssertEqual(array.count, 404U); + for (int i = 0; i < 100; ++i) { + [array removeValueAtIndex:(i * 2)]; + } + XCTAssertEqual(array.count, 304U); + for (int i = 0; i < 100; ++i) { + [array insertValue:14U atIndex:(i * 3)]; + } + XCTAssertEqual(array.count, 404U); + [array removeAll]; + XCTAssertEqual(array.count, 0U); +} + +@end + +//%PDDM-EXPAND ARRAY_TESTS(Int64, int64_t, 31LL, 32LL, 33LL, 34LL) +// This block of code is generated, do not edit it directly. + +#pragma mark - Int64 + +@interface GPBInt64ArrayTests : XCTestCase +@end + +@implementation GPBInt64ArrayTests + +- (void)testEmpty { + GPBInt64Array *array = [[GPBInt64Array alloc] init]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array release]; +} + +- (void)testOne { + GPBInt64Array *array = [GPBInt64Array arrayWithValue:31LL]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 1U); + XCTAssertEqual([array valueAtIndex:0], 31LL); + XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 31LL); + XCTAssertNotEqual(stop, NULL); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 31LL); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + static const int64_t kValues[] = { 31LL, 32LL, 33LL, 34LL }; + GPBInt64Array *array = + [[GPBInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 31LL); + XCTAssertEqual([array valueAtIndex:1], 32LL); + XCTAssertEqual([array valueAtIndex:2], 33LL); + XCTAssertEqual([array valueAtIndex:3], 34LL); + XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException); + __block NSUInteger idx2 = 0; + [array enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + // Stopping the enumeration. + idx2 = 0; + [array enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + XCTAssertNotEqual(idx, 3U); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 1U); + XCTAssertNotEqual(idx, 0U); + ++idx2; + }]; + [array release]; +} + +- (void)testEquality { + const int64_t kValues1[] = { 31LL, 32LL, 33LL }; + const int64_t kValues2[] = { 31LL, 34LL, 33LL }; + const int64_t kValues3[] = { 31LL, 32LL, 33LL, 34LL }; + GPBInt64Array *array1 = + [[GPBInt64Array alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1); + GPBInt64Array *array1prime = + [[GPBInt64Array alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1prime); + GPBInt64Array *array2 = + [[GPBInt64Array alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + GPBInt64Array *array3 = + [[GPBInt64Array alloc] initWithValues:kValues3 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(array3); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(array1, array1prime); + XCTAssertEqualObjects(array1, array1prime); + // Equal, so they must have same hash. + XCTAssertEqual([array1 hash], [array1prime hash]); + + // 1/2/3 shouldn't be equal. + XCTAssertNotEqualObjects(array1, array2); + XCTAssertNotEqualObjects(array1, array3); + XCTAssertNotEqualObjects(array2, array3); + + [array1 release]; + [array1prime release]; + [array2 release]; + [array3 release]; +} + +- (void)testCopy { + const int64_t kValues[] = { 31LL, 32LL, 33LL, 34LL }; + GPBInt64Array *array = + [[GPBInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBInt64Array *array2 = [array copy]; + XCTAssertNotNil(array2); + + // Should be new object but equal. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testArrayFromArray { + const int64_t kValues[] = { 31LL, 32LL, 33LL, 34LL }; + GPBInt64Array *array = + [[GPBInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBInt64Array *array2 = [GPBInt64Array arrayWithValueArray:array]; + XCTAssertNotNil(array2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testAdds { + GPBInt64Array *array = [GPBInt64Array array]; + XCTAssertNotNil(array); + + XCTAssertEqual(array.count, 0U); + [array addValue:31LL]; + XCTAssertEqual(array.count, 1U); + + const int64_t kValues1[] = { 32LL, 33LL }; + [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)]; + XCTAssertEqual(array.count, 3U); + + const int64_t kValues2[] = { 34LL, 31LL }; + GPBInt64Array *array2 = + [[GPBInt64Array alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + [array addValuesFromArray:array2]; + XCTAssertEqual(array.count, 5U); + + XCTAssertEqual([array valueAtIndex:0], 31LL); + XCTAssertEqual([array valueAtIndex:1], 32LL); + XCTAssertEqual([array valueAtIndex:2], 33LL); + XCTAssertEqual([array valueAtIndex:3], 34LL); + XCTAssertEqual([array valueAtIndex:4], 31LL); +} + +- (void)testInsert { + const int64_t kValues[] = { 31LL, 32LL, 33LL }; + GPBInt64Array *array = + [[GPBInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 3U); + + // First + [array insertValue:34LL atIndex:0]; + XCTAssertEqual(array.count, 4U); + + // Middle + [array insertValue:34LL atIndex:2]; + XCTAssertEqual(array.count, 5U); + + // End + [array insertValue:34LL atIndex:5]; + XCTAssertEqual(array.count, 6U); + + // Too far. + XCTAssertThrowsSpecificNamed([array insertValue:34LL atIndex:7], + NSException, NSRangeException); + + XCTAssertEqual([array valueAtIndex:0], 34LL); + XCTAssertEqual([array valueAtIndex:1], 31LL); + XCTAssertEqual([array valueAtIndex:2], 34LL); + XCTAssertEqual([array valueAtIndex:3], 32LL); + XCTAssertEqual([array valueAtIndex:4], 33LL); + XCTAssertEqual([array valueAtIndex:5], 34LL); +} + +- (void)testRemove { + const int64_t kValues[] = { 34LL, 31LL, 32LL, 34LL, 33LL, 34LL }; + GPBInt64Array *array = + [[GPBInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 6U); + + // First + [array removeValueAtIndex:0]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], 31LL); + + // Middle + [array removeValueAtIndex:2]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:2], 33LL); + + // End + [array removeValueAtIndex:3]; + XCTAssertEqual(array.count, 3U); + + XCTAssertEqual([array valueAtIndex:0], 31LL); + XCTAssertEqual([array valueAtIndex:1], 32LL); + XCTAssertEqual([array valueAtIndex:2], 33LL); + + // Too far. + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3], + NSException, NSRangeException); + + [array removeAll]; + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0], + NSException, NSRangeException); +} + +- (void)testInplaceMutation { + const int64_t kValues[] = { 31LL, 31LL, 33LL, 33LL }; + GPBInt64Array *array = + [[GPBInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + [array replaceValueAtIndex:1 withValue:32LL]; + [array replaceValueAtIndex:3 withValue:34LL]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 31LL); + XCTAssertEqual([array valueAtIndex:1], 32LL); + XCTAssertEqual([array valueAtIndex:2], 33LL); + XCTAssertEqual([array valueAtIndex:3], 34LL); + + XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:34LL], + NSException, NSRangeException); + + [array exchangeValueAtIndex:1 withValueAtIndex:3]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 31LL); + XCTAssertEqual([array valueAtIndex:1], 34LL); + XCTAssertEqual([array valueAtIndex:2], 33LL); + XCTAssertEqual([array valueAtIndex:3], 32LL); + + [array exchangeValueAtIndex:2 withValueAtIndex:0]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 33LL); + XCTAssertEqual([array valueAtIndex:1], 34LL); + XCTAssertEqual([array valueAtIndex:2], 31LL); + XCTAssertEqual([array valueAtIndex:3], 32LL); + + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1], + NSException, NSRangeException); + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4], + NSException, NSRangeException); +} + +- (void)testInternalResizing { + const int64_t kValues[] = { 31LL, 32LL, 33LL, 34LL }; + GPBInt64Array *array = + [[GPBInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + // Add/remove to trigger the intneral buffer to grow/shrink. + for (int i = 0; i < 100; ++i) { + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; + } + XCTAssertEqual(array.count, 404U); + for (int i = 0; i < 100; ++i) { + [array removeValueAtIndex:(i * 2)]; + } + XCTAssertEqual(array.count, 304U); + for (int i = 0; i < 100; ++i) { + [array insertValue:34LL atIndex:(i * 3)]; + } + XCTAssertEqual(array.count, 404U); + [array removeAll]; + XCTAssertEqual(array.count, 0U); +} + +@end + +//%PDDM-EXPAND ARRAY_TESTS(UInt64, uint64_t, 41ULL, 42ULL, 43ULL, 44ULL) +// This block of code is generated, do not edit it directly. + +#pragma mark - UInt64 + +@interface GPBUInt64ArrayTests : XCTestCase +@end + +@implementation GPBUInt64ArrayTests + +- (void)testEmpty { + GPBUInt64Array *array = [[GPBUInt64Array alloc] init]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array release]; +} + +- (void)testOne { + GPBUInt64Array *array = [GPBUInt64Array arrayWithValue:41ULL]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 1U); + XCTAssertEqual([array valueAtIndex:0], 41ULL); + XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 41ULL); + XCTAssertNotEqual(stop, NULL); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 41ULL); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + static const uint64_t kValues[] = { 41ULL, 42ULL, 43ULL, 44ULL }; + GPBUInt64Array *array = + [[GPBUInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 41ULL); + XCTAssertEqual([array valueAtIndex:1], 42ULL); + XCTAssertEqual([array valueAtIndex:2], 43ULL); + XCTAssertEqual([array valueAtIndex:3], 44ULL); + XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException); + __block NSUInteger idx2 = 0; + [array enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + // Stopping the enumeration. + idx2 = 0; + [array enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + XCTAssertNotEqual(idx, 3U); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 1U); + XCTAssertNotEqual(idx, 0U); + ++idx2; + }]; + [array release]; +} + +- (void)testEquality { + const uint64_t kValues1[] = { 41ULL, 42ULL, 43ULL }; + const uint64_t kValues2[] = { 41ULL, 44ULL, 43ULL }; + const uint64_t kValues3[] = { 41ULL, 42ULL, 43ULL, 44ULL }; + GPBUInt64Array *array1 = + [[GPBUInt64Array alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1); + GPBUInt64Array *array1prime = + [[GPBUInt64Array alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1prime); + GPBUInt64Array *array2 = + [[GPBUInt64Array alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + GPBUInt64Array *array3 = + [[GPBUInt64Array alloc] initWithValues:kValues3 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(array3); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(array1, array1prime); + XCTAssertEqualObjects(array1, array1prime); + // Equal, so they must have same hash. + XCTAssertEqual([array1 hash], [array1prime hash]); + + // 1/2/3 shouldn't be equal. + XCTAssertNotEqualObjects(array1, array2); + XCTAssertNotEqualObjects(array1, array3); + XCTAssertNotEqualObjects(array2, array3); + + [array1 release]; + [array1prime release]; + [array2 release]; + [array3 release]; +} + +- (void)testCopy { + const uint64_t kValues[] = { 41ULL, 42ULL, 43ULL, 44ULL }; + GPBUInt64Array *array = + [[GPBUInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBUInt64Array *array2 = [array copy]; + XCTAssertNotNil(array2); + + // Should be new object but equal. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testArrayFromArray { + const uint64_t kValues[] = { 41ULL, 42ULL, 43ULL, 44ULL }; + GPBUInt64Array *array = + [[GPBUInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBUInt64Array *array2 = [GPBUInt64Array arrayWithValueArray:array]; + XCTAssertNotNil(array2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testAdds { + GPBUInt64Array *array = [GPBUInt64Array array]; + XCTAssertNotNil(array); + + XCTAssertEqual(array.count, 0U); + [array addValue:41ULL]; + XCTAssertEqual(array.count, 1U); + + const uint64_t kValues1[] = { 42ULL, 43ULL }; + [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)]; + XCTAssertEqual(array.count, 3U); + + const uint64_t kValues2[] = { 44ULL, 41ULL }; + GPBUInt64Array *array2 = + [[GPBUInt64Array alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + [array addValuesFromArray:array2]; + XCTAssertEqual(array.count, 5U); + + XCTAssertEqual([array valueAtIndex:0], 41ULL); + XCTAssertEqual([array valueAtIndex:1], 42ULL); + XCTAssertEqual([array valueAtIndex:2], 43ULL); + XCTAssertEqual([array valueAtIndex:3], 44ULL); + XCTAssertEqual([array valueAtIndex:4], 41ULL); +} + +- (void)testInsert { + const uint64_t kValues[] = { 41ULL, 42ULL, 43ULL }; + GPBUInt64Array *array = + [[GPBUInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 3U); + + // First + [array insertValue:44ULL atIndex:0]; + XCTAssertEqual(array.count, 4U); + + // Middle + [array insertValue:44ULL atIndex:2]; + XCTAssertEqual(array.count, 5U); + + // End + [array insertValue:44ULL atIndex:5]; + XCTAssertEqual(array.count, 6U); + + // Too far. + XCTAssertThrowsSpecificNamed([array insertValue:44ULL atIndex:7], + NSException, NSRangeException); + + XCTAssertEqual([array valueAtIndex:0], 44ULL); + XCTAssertEqual([array valueAtIndex:1], 41ULL); + XCTAssertEqual([array valueAtIndex:2], 44ULL); + XCTAssertEqual([array valueAtIndex:3], 42ULL); + XCTAssertEqual([array valueAtIndex:4], 43ULL); + XCTAssertEqual([array valueAtIndex:5], 44ULL); +} + +- (void)testRemove { + const uint64_t kValues[] = { 44ULL, 41ULL, 42ULL, 44ULL, 43ULL, 44ULL }; + GPBUInt64Array *array = + [[GPBUInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 6U); + + // First + [array removeValueAtIndex:0]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], 41ULL); + + // Middle + [array removeValueAtIndex:2]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:2], 43ULL); + + // End + [array removeValueAtIndex:3]; + XCTAssertEqual(array.count, 3U); + + XCTAssertEqual([array valueAtIndex:0], 41ULL); + XCTAssertEqual([array valueAtIndex:1], 42ULL); + XCTAssertEqual([array valueAtIndex:2], 43ULL); + + // Too far. + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3], + NSException, NSRangeException); + + [array removeAll]; + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0], + NSException, NSRangeException); +} + +- (void)testInplaceMutation { + const uint64_t kValues[] = { 41ULL, 41ULL, 43ULL, 43ULL }; + GPBUInt64Array *array = + [[GPBUInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + [array replaceValueAtIndex:1 withValue:42ULL]; + [array replaceValueAtIndex:3 withValue:44ULL]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 41ULL); + XCTAssertEqual([array valueAtIndex:1], 42ULL); + XCTAssertEqual([array valueAtIndex:2], 43ULL); + XCTAssertEqual([array valueAtIndex:3], 44ULL); + + XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:44ULL], + NSException, NSRangeException); + + [array exchangeValueAtIndex:1 withValueAtIndex:3]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 41ULL); + XCTAssertEqual([array valueAtIndex:1], 44ULL); + XCTAssertEqual([array valueAtIndex:2], 43ULL); + XCTAssertEqual([array valueAtIndex:3], 42ULL); + + [array exchangeValueAtIndex:2 withValueAtIndex:0]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 43ULL); + XCTAssertEqual([array valueAtIndex:1], 44ULL); + XCTAssertEqual([array valueAtIndex:2], 41ULL); + XCTAssertEqual([array valueAtIndex:3], 42ULL); + + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1], + NSException, NSRangeException); + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4], + NSException, NSRangeException); +} + +- (void)testInternalResizing { + const uint64_t kValues[] = { 41ULL, 42ULL, 43ULL, 44ULL }; + GPBUInt64Array *array = + [[GPBUInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + // Add/remove to trigger the intneral buffer to grow/shrink. + for (int i = 0; i < 100; ++i) { + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; + } + XCTAssertEqual(array.count, 404U); + for (int i = 0; i < 100; ++i) { + [array removeValueAtIndex:(i * 2)]; + } + XCTAssertEqual(array.count, 304U); + for (int i = 0; i < 100; ++i) { + [array insertValue:44ULL atIndex:(i * 3)]; + } + XCTAssertEqual(array.count, 404U); + [array removeAll]; + XCTAssertEqual(array.count, 0U); +} + +@end + +//%PDDM-EXPAND ARRAY_TESTS(Float, float, 51.f, 52.f, 53.f, 54.f) +// This block of code is generated, do not edit it directly. + +#pragma mark - Float + +@interface GPBFloatArrayTests : XCTestCase +@end + +@implementation GPBFloatArrayTests + +- (void)testEmpty { + GPBFloatArray *array = [[GPBFloatArray alloc] init]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(float value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(float value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array release]; +} + +- (void)testOne { + GPBFloatArray *array = [GPBFloatArray arrayWithValue:51.f]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 1U); + XCTAssertEqual([array valueAtIndex:0], 51.f); + XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(float value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 51.f); + XCTAssertNotEqual(stop, NULL); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(float value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 51.f); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + static const float kValues[] = { 51.f, 52.f, 53.f, 54.f }; + GPBFloatArray *array = + [[GPBFloatArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 51.f); + XCTAssertEqual([array valueAtIndex:1], 52.f); + XCTAssertEqual([array valueAtIndex:2], 53.f); + XCTAssertEqual([array valueAtIndex:3], 54.f); + XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException); + __block NSUInteger idx2 = 0; + [array enumerateValuesWithBlock:^(float value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(float value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + // Stopping the enumeration. + idx2 = 0; + [array enumerateValuesWithBlock:^(float value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + XCTAssertNotEqual(idx, 3U); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(float value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 1U); + XCTAssertNotEqual(idx, 0U); + ++idx2; + }]; + [array release]; +} + +- (void)testEquality { + const float kValues1[] = { 51.f, 52.f, 53.f }; + const float kValues2[] = { 51.f, 54.f, 53.f }; + const float kValues3[] = { 51.f, 52.f, 53.f, 54.f }; + GPBFloatArray *array1 = + [[GPBFloatArray alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1); + GPBFloatArray *array1prime = + [[GPBFloatArray alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1prime); + GPBFloatArray *array2 = + [[GPBFloatArray alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + GPBFloatArray *array3 = + [[GPBFloatArray alloc] initWithValues:kValues3 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(array3); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(array1, array1prime); + XCTAssertEqualObjects(array1, array1prime); + // Equal, so they must have same hash. + XCTAssertEqual([array1 hash], [array1prime hash]); + + // 1/2/3 shouldn't be equal. + XCTAssertNotEqualObjects(array1, array2); + XCTAssertNotEqualObjects(array1, array3); + XCTAssertNotEqualObjects(array2, array3); + + [array1 release]; + [array1prime release]; + [array2 release]; + [array3 release]; +} + +- (void)testCopy { + const float kValues[] = { 51.f, 52.f, 53.f, 54.f }; + GPBFloatArray *array = + [[GPBFloatArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBFloatArray *array2 = [array copy]; + XCTAssertNotNil(array2); + + // Should be new object but equal. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testArrayFromArray { + const float kValues[] = { 51.f, 52.f, 53.f, 54.f }; + GPBFloatArray *array = + [[GPBFloatArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBFloatArray *array2 = [GPBFloatArray arrayWithValueArray:array]; + XCTAssertNotNil(array2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testAdds { + GPBFloatArray *array = [GPBFloatArray array]; + XCTAssertNotNil(array); + + XCTAssertEqual(array.count, 0U); + [array addValue:51.f]; + XCTAssertEqual(array.count, 1U); + + const float kValues1[] = { 52.f, 53.f }; + [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)]; + XCTAssertEqual(array.count, 3U); + + const float kValues2[] = { 54.f, 51.f }; + GPBFloatArray *array2 = + [[GPBFloatArray alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + [array addValuesFromArray:array2]; + XCTAssertEqual(array.count, 5U); + + XCTAssertEqual([array valueAtIndex:0], 51.f); + XCTAssertEqual([array valueAtIndex:1], 52.f); + XCTAssertEqual([array valueAtIndex:2], 53.f); + XCTAssertEqual([array valueAtIndex:3], 54.f); + XCTAssertEqual([array valueAtIndex:4], 51.f); +} + +- (void)testInsert { + const float kValues[] = { 51.f, 52.f, 53.f }; + GPBFloatArray *array = + [[GPBFloatArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 3U); + + // First + [array insertValue:54.f atIndex:0]; + XCTAssertEqual(array.count, 4U); + + // Middle + [array insertValue:54.f atIndex:2]; + XCTAssertEqual(array.count, 5U); + + // End + [array insertValue:54.f atIndex:5]; + XCTAssertEqual(array.count, 6U); + + // Too far. + XCTAssertThrowsSpecificNamed([array insertValue:54.f atIndex:7], + NSException, NSRangeException); + + XCTAssertEqual([array valueAtIndex:0], 54.f); + XCTAssertEqual([array valueAtIndex:1], 51.f); + XCTAssertEqual([array valueAtIndex:2], 54.f); + XCTAssertEqual([array valueAtIndex:3], 52.f); + XCTAssertEqual([array valueAtIndex:4], 53.f); + XCTAssertEqual([array valueAtIndex:5], 54.f); +} + +- (void)testRemove { + const float kValues[] = { 54.f, 51.f, 52.f, 54.f, 53.f, 54.f }; + GPBFloatArray *array = + [[GPBFloatArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 6U); + + // First + [array removeValueAtIndex:0]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], 51.f); + + // Middle + [array removeValueAtIndex:2]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:2], 53.f); + + // End + [array removeValueAtIndex:3]; + XCTAssertEqual(array.count, 3U); + + XCTAssertEqual([array valueAtIndex:0], 51.f); + XCTAssertEqual([array valueAtIndex:1], 52.f); + XCTAssertEqual([array valueAtIndex:2], 53.f); + + // Too far. + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3], + NSException, NSRangeException); + + [array removeAll]; + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0], + NSException, NSRangeException); +} + +- (void)testInplaceMutation { + const float kValues[] = { 51.f, 51.f, 53.f, 53.f }; + GPBFloatArray *array = + [[GPBFloatArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + [array replaceValueAtIndex:1 withValue:52.f]; + [array replaceValueAtIndex:3 withValue:54.f]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 51.f); + XCTAssertEqual([array valueAtIndex:1], 52.f); + XCTAssertEqual([array valueAtIndex:2], 53.f); + XCTAssertEqual([array valueAtIndex:3], 54.f); + + XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:54.f], + NSException, NSRangeException); + + [array exchangeValueAtIndex:1 withValueAtIndex:3]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 51.f); + XCTAssertEqual([array valueAtIndex:1], 54.f); + XCTAssertEqual([array valueAtIndex:2], 53.f); + XCTAssertEqual([array valueAtIndex:3], 52.f); + + [array exchangeValueAtIndex:2 withValueAtIndex:0]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 53.f); + XCTAssertEqual([array valueAtIndex:1], 54.f); + XCTAssertEqual([array valueAtIndex:2], 51.f); + XCTAssertEqual([array valueAtIndex:3], 52.f); + + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1], + NSException, NSRangeException); + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4], + NSException, NSRangeException); +} + +- (void)testInternalResizing { + const float kValues[] = { 51.f, 52.f, 53.f, 54.f }; + GPBFloatArray *array = + [[GPBFloatArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + // Add/remove to trigger the intneral buffer to grow/shrink. + for (int i = 0; i < 100; ++i) { + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; + } + XCTAssertEqual(array.count, 404U); + for (int i = 0; i < 100; ++i) { + [array removeValueAtIndex:(i * 2)]; + } + XCTAssertEqual(array.count, 304U); + for (int i = 0; i < 100; ++i) { + [array insertValue:54.f atIndex:(i * 3)]; + } + XCTAssertEqual(array.count, 404U); + [array removeAll]; + XCTAssertEqual(array.count, 0U); +} + +@end + +//%PDDM-EXPAND ARRAY_TESTS(Double, double, 61., 62., 63., 64.) +// This block of code is generated, do not edit it directly. + +#pragma mark - Double + +@interface GPBDoubleArrayTests : XCTestCase +@end + +@implementation GPBDoubleArrayTests + +- (void)testEmpty { + GPBDoubleArray *array = [[GPBDoubleArray alloc] init]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(double value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(double value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array release]; +} + +- (void)testOne { + GPBDoubleArray *array = [GPBDoubleArray arrayWithValue:61.]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 1U); + XCTAssertEqual([array valueAtIndex:0], 61.); + XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(double value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 61.); + XCTAssertNotEqual(stop, NULL); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(double value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 61.); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + static const double kValues[] = { 61., 62., 63., 64. }; + GPBDoubleArray *array = + [[GPBDoubleArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 61.); + XCTAssertEqual([array valueAtIndex:1], 62.); + XCTAssertEqual([array valueAtIndex:2], 63.); + XCTAssertEqual([array valueAtIndex:3], 64.); + XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException); + __block NSUInteger idx2 = 0; + [array enumerateValuesWithBlock:^(double value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(double value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + // Stopping the enumeration. + idx2 = 0; + [array enumerateValuesWithBlock:^(double value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + XCTAssertNotEqual(idx, 3U); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(double value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 1U); + XCTAssertNotEqual(idx, 0U); + ++idx2; + }]; + [array release]; +} + +- (void)testEquality { + const double kValues1[] = { 61., 62., 63. }; + const double kValues2[] = { 61., 64., 63. }; + const double kValues3[] = { 61., 62., 63., 64. }; + GPBDoubleArray *array1 = + [[GPBDoubleArray alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1); + GPBDoubleArray *array1prime = + [[GPBDoubleArray alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1prime); + GPBDoubleArray *array2 = + [[GPBDoubleArray alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + GPBDoubleArray *array3 = + [[GPBDoubleArray alloc] initWithValues:kValues3 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(array3); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(array1, array1prime); + XCTAssertEqualObjects(array1, array1prime); + // Equal, so they must have same hash. + XCTAssertEqual([array1 hash], [array1prime hash]); + + // 1/2/3 shouldn't be equal. + XCTAssertNotEqualObjects(array1, array2); + XCTAssertNotEqualObjects(array1, array3); + XCTAssertNotEqualObjects(array2, array3); + + [array1 release]; + [array1prime release]; + [array2 release]; + [array3 release]; +} + +- (void)testCopy { + const double kValues[] = { 61., 62., 63., 64. }; + GPBDoubleArray *array = + [[GPBDoubleArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBDoubleArray *array2 = [array copy]; + XCTAssertNotNil(array2); + + // Should be new object but equal. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testArrayFromArray { + const double kValues[] = { 61., 62., 63., 64. }; + GPBDoubleArray *array = + [[GPBDoubleArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBDoubleArray *array2 = [GPBDoubleArray arrayWithValueArray:array]; + XCTAssertNotNil(array2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testAdds { + GPBDoubleArray *array = [GPBDoubleArray array]; + XCTAssertNotNil(array); + + XCTAssertEqual(array.count, 0U); + [array addValue:61.]; + XCTAssertEqual(array.count, 1U); + + const double kValues1[] = { 62., 63. }; + [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)]; + XCTAssertEqual(array.count, 3U); + + const double kValues2[] = { 64., 61. }; + GPBDoubleArray *array2 = + [[GPBDoubleArray alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + [array addValuesFromArray:array2]; + XCTAssertEqual(array.count, 5U); + + XCTAssertEqual([array valueAtIndex:0], 61.); + XCTAssertEqual([array valueAtIndex:1], 62.); + XCTAssertEqual([array valueAtIndex:2], 63.); + XCTAssertEqual([array valueAtIndex:3], 64.); + XCTAssertEqual([array valueAtIndex:4], 61.); +} + +- (void)testInsert { + const double kValues[] = { 61., 62., 63. }; + GPBDoubleArray *array = + [[GPBDoubleArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 3U); + + // First + [array insertValue:64. atIndex:0]; + XCTAssertEqual(array.count, 4U); + + // Middle + [array insertValue:64. atIndex:2]; + XCTAssertEqual(array.count, 5U); + + // End + [array insertValue:64. atIndex:5]; + XCTAssertEqual(array.count, 6U); + + // Too far. + XCTAssertThrowsSpecificNamed([array insertValue:64. atIndex:7], + NSException, NSRangeException); + + XCTAssertEqual([array valueAtIndex:0], 64.); + XCTAssertEqual([array valueAtIndex:1], 61.); + XCTAssertEqual([array valueAtIndex:2], 64.); + XCTAssertEqual([array valueAtIndex:3], 62.); + XCTAssertEqual([array valueAtIndex:4], 63.); + XCTAssertEqual([array valueAtIndex:5], 64.); +} + +- (void)testRemove { + const double kValues[] = { 64., 61., 62., 64., 63., 64. }; + GPBDoubleArray *array = + [[GPBDoubleArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 6U); + + // First + [array removeValueAtIndex:0]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], 61.); + + // Middle + [array removeValueAtIndex:2]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:2], 63.); + + // End + [array removeValueAtIndex:3]; + XCTAssertEqual(array.count, 3U); + + XCTAssertEqual([array valueAtIndex:0], 61.); + XCTAssertEqual([array valueAtIndex:1], 62.); + XCTAssertEqual([array valueAtIndex:2], 63.); + + // Too far. + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3], + NSException, NSRangeException); + + [array removeAll]; + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0], + NSException, NSRangeException); +} + +- (void)testInplaceMutation { + const double kValues[] = { 61., 61., 63., 63. }; + GPBDoubleArray *array = + [[GPBDoubleArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + [array replaceValueAtIndex:1 withValue:62.]; + [array replaceValueAtIndex:3 withValue:64.]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 61.); + XCTAssertEqual([array valueAtIndex:1], 62.); + XCTAssertEqual([array valueAtIndex:2], 63.); + XCTAssertEqual([array valueAtIndex:3], 64.); + + XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:64.], + NSException, NSRangeException); + + [array exchangeValueAtIndex:1 withValueAtIndex:3]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 61.); + XCTAssertEqual([array valueAtIndex:1], 64.); + XCTAssertEqual([array valueAtIndex:2], 63.); + XCTAssertEqual([array valueAtIndex:3], 62.); + + [array exchangeValueAtIndex:2 withValueAtIndex:0]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 63.); + XCTAssertEqual([array valueAtIndex:1], 64.); + XCTAssertEqual([array valueAtIndex:2], 61.); + XCTAssertEqual([array valueAtIndex:3], 62.); + + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1], + NSException, NSRangeException); + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4], + NSException, NSRangeException); +} + +- (void)testInternalResizing { + const double kValues[] = { 61., 62., 63., 64. }; + GPBDoubleArray *array = + [[GPBDoubleArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + // Add/remove to trigger the intneral buffer to grow/shrink. + for (int i = 0; i < 100; ++i) { + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; + } + XCTAssertEqual(array.count, 404U); + for (int i = 0; i < 100; ++i) { + [array removeValueAtIndex:(i * 2)]; + } + XCTAssertEqual(array.count, 304U); + for (int i = 0; i < 100; ++i) { + [array insertValue:64. atIndex:(i * 3)]; + } + XCTAssertEqual(array.count, 404U); + [array removeAll]; + XCTAssertEqual(array.count, 0U); +} + +@end + +//%PDDM-EXPAND ARRAY_TESTS(Bool, BOOL, TRUE, TRUE, FALSE, FALSE) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool + +@interface GPBBoolArrayTests : XCTestCase +@end + +@implementation GPBBoolArrayTests + +- (void)testEmpty { + GPBBoolArray *array = [[GPBBoolArray alloc] init]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(BOOL value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(BOOL value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array release]; +} + +- (void)testOne { + GPBBoolArray *array = [GPBBoolArray arrayWithValue:TRUE]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 1U); + XCTAssertEqual([array valueAtIndex:0], TRUE); + XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(BOOL value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, TRUE); + XCTAssertNotEqual(stop, NULL); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(BOOL value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, TRUE); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + static const BOOL kValues[] = { TRUE, TRUE, FALSE, FALSE }; + GPBBoolArray *array = + [[GPBBoolArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], TRUE); + XCTAssertEqual([array valueAtIndex:1], TRUE); + XCTAssertEqual([array valueAtIndex:2], FALSE); + XCTAssertEqual([array valueAtIndex:3], FALSE); + XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException); + __block NSUInteger idx2 = 0; + [array enumerateValuesWithBlock:^(BOOL value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(BOOL value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + // Stopping the enumeration. + idx2 = 0; + [array enumerateValuesWithBlock:^(BOOL value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + XCTAssertNotEqual(idx, 3U); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(BOOL value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 1U); + XCTAssertNotEqual(idx, 0U); + ++idx2; + }]; + [array release]; +} + +- (void)testEquality { + const BOOL kValues1[] = { TRUE, TRUE, FALSE }; + const BOOL kValues2[] = { TRUE, FALSE, FALSE }; + const BOOL kValues3[] = { TRUE, TRUE, FALSE, FALSE }; + GPBBoolArray *array1 = + [[GPBBoolArray alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1); + GPBBoolArray *array1prime = + [[GPBBoolArray alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1prime); + GPBBoolArray *array2 = + [[GPBBoolArray alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + GPBBoolArray *array3 = + [[GPBBoolArray alloc] initWithValues:kValues3 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(array3); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(array1, array1prime); + XCTAssertEqualObjects(array1, array1prime); + // Equal, so they must have same hash. + XCTAssertEqual([array1 hash], [array1prime hash]); + + // 1/2/3 shouldn't be equal. + XCTAssertNotEqualObjects(array1, array2); + XCTAssertNotEqualObjects(array1, array3); + XCTAssertNotEqualObjects(array2, array3); + + [array1 release]; + [array1prime release]; + [array2 release]; + [array3 release]; +} + +- (void)testCopy { + const BOOL kValues[] = { TRUE, TRUE, FALSE, FALSE }; + GPBBoolArray *array = + [[GPBBoolArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBBoolArray *array2 = [array copy]; + XCTAssertNotNil(array2); + + // Should be new object but equal. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testArrayFromArray { + const BOOL kValues[] = { TRUE, TRUE, FALSE, FALSE }; + GPBBoolArray *array = + [[GPBBoolArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBBoolArray *array2 = [GPBBoolArray arrayWithValueArray:array]; + XCTAssertNotNil(array2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testAdds { + GPBBoolArray *array = [GPBBoolArray array]; + XCTAssertNotNil(array); + + XCTAssertEqual(array.count, 0U); + [array addValue:TRUE]; + XCTAssertEqual(array.count, 1U); + + const BOOL kValues1[] = { TRUE, FALSE }; + [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)]; + XCTAssertEqual(array.count, 3U); + + const BOOL kValues2[] = { FALSE, TRUE }; + GPBBoolArray *array2 = + [[GPBBoolArray alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + [array addValuesFromArray:array2]; + XCTAssertEqual(array.count, 5U); + + XCTAssertEqual([array valueAtIndex:0], TRUE); + XCTAssertEqual([array valueAtIndex:1], TRUE); + XCTAssertEqual([array valueAtIndex:2], FALSE); + XCTAssertEqual([array valueAtIndex:3], FALSE); + XCTAssertEqual([array valueAtIndex:4], TRUE); +} + +- (void)testInsert { + const BOOL kValues[] = { TRUE, TRUE, FALSE }; + GPBBoolArray *array = + [[GPBBoolArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 3U); + + // First + [array insertValue:FALSE atIndex:0]; + XCTAssertEqual(array.count, 4U); + + // Middle + [array insertValue:FALSE atIndex:2]; + XCTAssertEqual(array.count, 5U); + + // End + [array insertValue:FALSE atIndex:5]; + XCTAssertEqual(array.count, 6U); + + // Too far. + XCTAssertThrowsSpecificNamed([array insertValue:FALSE atIndex:7], + NSException, NSRangeException); + + XCTAssertEqual([array valueAtIndex:0], FALSE); + XCTAssertEqual([array valueAtIndex:1], TRUE); + XCTAssertEqual([array valueAtIndex:2], FALSE); + XCTAssertEqual([array valueAtIndex:3], TRUE); + XCTAssertEqual([array valueAtIndex:4], FALSE); + XCTAssertEqual([array valueAtIndex:5], FALSE); +} + +- (void)testRemove { + const BOOL kValues[] = { FALSE, TRUE, TRUE, FALSE, FALSE, FALSE }; + GPBBoolArray *array = + [[GPBBoolArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 6U); + + // First + [array removeValueAtIndex:0]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], TRUE); + + // Middle + [array removeValueAtIndex:2]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:2], FALSE); + + // End + [array removeValueAtIndex:3]; + XCTAssertEqual(array.count, 3U); + + XCTAssertEqual([array valueAtIndex:0], TRUE); + XCTAssertEqual([array valueAtIndex:1], TRUE); + XCTAssertEqual([array valueAtIndex:2], FALSE); + + // Too far. + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3], + NSException, NSRangeException); + + [array removeAll]; + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0], + NSException, NSRangeException); +} + +- (void)testInplaceMutation { + const BOOL kValues[] = { TRUE, TRUE, FALSE, FALSE }; + GPBBoolArray *array = + [[GPBBoolArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + [array replaceValueAtIndex:1 withValue:TRUE]; + [array replaceValueAtIndex:3 withValue:FALSE]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], TRUE); + XCTAssertEqual([array valueAtIndex:1], TRUE); + XCTAssertEqual([array valueAtIndex:2], FALSE); + XCTAssertEqual([array valueAtIndex:3], FALSE); + + XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:FALSE], + NSException, NSRangeException); + + [array exchangeValueAtIndex:1 withValueAtIndex:3]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], TRUE); + XCTAssertEqual([array valueAtIndex:1], FALSE); + XCTAssertEqual([array valueAtIndex:2], FALSE); + XCTAssertEqual([array valueAtIndex:3], TRUE); + + [array exchangeValueAtIndex:2 withValueAtIndex:0]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], FALSE); + XCTAssertEqual([array valueAtIndex:1], FALSE); + XCTAssertEqual([array valueAtIndex:2], TRUE); + XCTAssertEqual([array valueAtIndex:3], TRUE); + + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1], + NSException, NSRangeException); + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4], + NSException, NSRangeException); +} + +- (void)testInternalResizing { + const BOOL kValues[] = { TRUE, TRUE, FALSE, FALSE }; + GPBBoolArray *array = + [[GPBBoolArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + // Add/remove to trigger the intneral buffer to grow/shrink. + for (int i = 0; i < 100; ++i) { + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; + } + XCTAssertEqual(array.count, 404U); + for (int i = 0; i < 100; ++i) { + [array removeValueAtIndex:(i * 2)]; + } + XCTAssertEqual(array.count, 304U); + for (int i = 0; i < 100; ++i) { + [array insertValue:FALSE atIndex:(i * 3)]; + } + XCTAssertEqual(array.count, 404U); + [array removeAll]; + XCTAssertEqual(array.count, 0U); +} + +@end + +//%PDDM-EXPAND ARRAY_TESTS2(Enum, int32_t, 71, 72, 73, 74, Raw) +// This block of code is generated, do not edit it directly. + +#pragma mark - Enum + +@interface GPBEnumArrayTests : XCTestCase +@end + +@implementation GPBEnumArrayTests + +- (void)testEmpty { + GPBEnumArray *array = [[GPBEnumArray alloc] init]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array release]; +} + +- (void)testOne { + GPBEnumArray *array = [GPBEnumArray arrayWithValue:71]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 1U); + XCTAssertEqual([array valueAtIndex:0], 71); + XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 71); + XCTAssertNotEqual(stop, NULL); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 71); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + static const int32_t kValues[] = { 71, 72, 73, 74 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 71); + XCTAssertEqual([array valueAtIndex:1], 72); + XCTAssertEqual([array valueAtIndex:2], 73); + XCTAssertEqual([array valueAtIndex:3], 74); + XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException); + __block NSUInteger idx2 = 0; + [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + // Stopping the enumeration. + idx2 = 0; + [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + XCTAssertNotEqual(idx, 3U); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 1U); + XCTAssertNotEqual(idx, 0U); + ++idx2; + }]; + [array release]; +} + +- (void)testEquality { + const int32_t kValues1[] = { 71, 72, 73 }; + const int32_t kValues2[] = { 71, 74, 73 }; + const int32_t kValues3[] = { 71, 72, 73, 74 }; + GPBEnumArray *array1 = + [[GPBEnumArray alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1); + GPBEnumArray *array1prime = + [[GPBEnumArray alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1prime); + GPBEnumArray *array2 = + [[GPBEnumArray alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + GPBEnumArray *array3 = + [[GPBEnumArray alloc] initWithValues:kValues3 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(array3); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(array1, array1prime); + XCTAssertEqualObjects(array1, array1prime); + // Equal, so they must have same hash. + XCTAssertEqual([array1 hash], [array1prime hash]); + + // 1/2/3 shouldn't be equal. + XCTAssertNotEqualObjects(array1, array2); + XCTAssertNotEqualObjects(array1, array3); + XCTAssertNotEqualObjects(array2, array3); + + [array1 release]; + [array1prime release]; + [array2 release]; + [array3 release]; +} + +- (void)testCopy { + const int32_t kValues[] = { 71, 72, 73, 74 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBEnumArray *array2 = [array copy]; + XCTAssertNotNil(array2); + + // Should be new object but equal. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testArrayFromArray { + const int32_t kValues[] = { 71, 72, 73, 74 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBEnumArray *array2 = [GPBEnumArray arrayWithValueArray:array]; + XCTAssertNotNil(array2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testAdds { + GPBEnumArray *array = [GPBEnumArray array]; + XCTAssertNotNil(array); + + XCTAssertEqual(array.count, 0U); + [array addValue:71]; + XCTAssertEqual(array.count, 1U); + + const int32_t kValues1[] = { 72, 73 }; + [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)]; + XCTAssertEqual(array.count, 3U); + + const int32_t kValues2[] = { 74, 71 }; + GPBEnumArray *array2 = + [[GPBEnumArray alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + [array addRawValuesFromArray:array2]; + XCTAssertEqual(array.count, 5U); + + XCTAssertEqual([array valueAtIndex:0], 71); + XCTAssertEqual([array valueAtIndex:1], 72); + XCTAssertEqual([array valueAtIndex:2], 73); + XCTAssertEqual([array valueAtIndex:3], 74); + XCTAssertEqual([array valueAtIndex:4], 71); +} + +- (void)testInsert { + const int32_t kValues[] = { 71, 72, 73 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 3U); + + // First + [array insertValue:74 atIndex:0]; + XCTAssertEqual(array.count, 4U); + + // Middle + [array insertValue:74 atIndex:2]; + XCTAssertEqual(array.count, 5U); + + // End + [array insertValue:74 atIndex:5]; + XCTAssertEqual(array.count, 6U); + + // Too far. + XCTAssertThrowsSpecificNamed([array insertValue:74 atIndex:7], + NSException, NSRangeException); + + XCTAssertEqual([array valueAtIndex:0], 74); + XCTAssertEqual([array valueAtIndex:1], 71); + XCTAssertEqual([array valueAtIndex:2], 74); + XCTAssertEqual([array valueAtIndex:3], 72); + XCTAssertEqual([array valueAtIndex:4], 73); + XCTAssertEqual([array valueAtIndex:5], 74); +} + +- (void)testRemove { + const int32_t kValues[] = { 74, 71, 72, 74, 73, 74 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 6U); + + // First + [array removeValueAtIndex:0]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], 71); + + // Middle + [array removeValueAtIndex:2]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:2], 73); + + // End + [array removeValueAtIndex:3]; + XCTAssertEqual(array.count, 3U); + + XCTAssertEqual([array valueAtIndex:0], 71); + XCTAssertEqual([array valueAtIndex:1], 72); + XCTAssertEqual([array valueAtIndex:2], 73); + + // Too far. + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3], + NSException, NSRangeException); + + [array removeAll]; + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0], + NSException, NSRangeException); +} + +- (void)testInplaceMutation { + const int32_t kValues[] = { 71, 71, 73, 73 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + [array replaceValueAtIndex:1 withValue:72]; + [array replaceValueAtIndex:3 withValue:74]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 71); + XCTAssertEqual([array valueAtIndex:1], 72); + XCTAssertEqual([array valueAtIndex:2], 73); + XCTAssertEqual([array valueAtIndex:3], 74); + + XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:74], + NSException, NSRangeException); + + [array exchangeValueAtIndex:1 withValueAtIndex:3]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 71); + XCTAssertEqual([array valueAtIndex:1], 74); + XCTAssertEqual([array valueAtIndex:2], 73); + XCTAssertEqual([array valueAtIndex:3], 72); + + [array exchangeValueAtIndex:2 withValueAtIndex:0]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 73); + XCTAssertEqual([array valueAtIndex:1], 74); + XCTAssertEqual([array valueAtIndex:2], 71); + XCTAssertEqual([array valueAtIndex:3], 72); + + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1], + NSException, NSRangeException); + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4], + NSException, NSRangeException); +} + +- (void)testInternalResizing { + const int32_t kValues[] = { 71, 72, 73, 74 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + // Add/remove to trigger the intneral buffer to grow/shrink. + for (int i = 0; i < 100; ++i) { + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; + } + XCTAssertEqual(array.count, 404U); + for (int i = 0; i < 100; ++i) { + [array removeValueAtIndex:(i * 2)]; + } + XCTAssertEqual(array.count, 304U); + for (int i = 0; i < 100; ++i) { + [array insertValue:74 atIndex:(i * 3)]; + } + XCTAssertEqual(array.count, 404U); + [array removeAll]; + XCTAssertEqual(array.count, 0U); +} + +@end + +//%PDDM-EXPAND-END (8 expansions) + +#pragma mark - Non macro-based Enum tests + +// These are hand written tests to cover the verification and raw methods. + +@interface GPBEnumArrayCustomTests : XCTestCase +@end + +@implementation GPBEnumArrayCustomTests + +- (void)testRawBasics { + static const int32_t kValues[] = { 71, 272, 73, 374 }; + static const int32_t kValuesFiltered[] = { + 71, kGPBUnrecognizedEnumeratorValue, 73, kGPBUnrecognizedEnumeratorValue + }; + XCTAssertEqual(GPBARRAYSIZE(kValues), GPBARRAYSIZE(kValuesFiltered)); + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 4U); + GPBEnumValidationFunc func = TestingEnum_IsValidValue; + XCTAssertEqual(array.validationFunc, func); + XCTAssertEqual([array rawValueAtIndex:0], 71); + XCTAssertEqual([array rawValueAtIndex:1], 272); + XCTAssertEqual([array valueAtIndex:1], kGPBUnrecognizedEnumeratorValue); + XCTAssertEqual([array rawValueAtIndex:2], 73); + XCTAssertEqual([array rawValueAtIndex:3], 374); + XCTAssertEqual([array valueAtIndex:3], kGPBUnrecognizedEnumeratorValue); + XCTAssertThrowsSpecificNamed([array rawValueAtIndex:4], NSException, NSRangeException); + __block NSUInteger idx2 = 0; + [array enumerateRawValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValuesFiltered[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + idx2 = 0; + [array enumerateRawValuesWithOptions:NSEnumerationReverse + usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValuesFiltered[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + // Stopping the enumeration. + idx2 = 0; + [array enumerateRawValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + XCTAssertNotEqual(idx, 3U); + ++idx2; + }]; + idx2 = 0; + [array enumerateRawValuesWithOptions:NSEnumerationReverse + usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 1U); + XCTAssertNotEqual(idx, 0U); + ++idx2; + }]; + [array release]; +} + +- (void)testEquality { + const int32_t kValues1[] = { 71, 72, 173 }; // With unknown value + const int32_t kValues2[] = { 71, 74, 173 }; // With unknown value + const int32_t kValues3[] = { 71, 72, 173, 74 }; // With unknown value + GPBEnumArray *array1 = + [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1); + GPBEnumArray *array1prime = + [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue2 + rawValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1prime); + GPBEnumArray *array2 = + [[GPBEnumArray alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + GPBEnumArray *array3 = + [[GPBEnumArray alloc] initWithValues:kValues3 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(array3); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(array1, array1prime); + XCTAssertEqualObjects(array1, array1prime); + // Equal, so they must have same hash. + XCTAssertEqual([array1 hash], [array1prime hash]); + // But different validation functions. + XCTAssertNotEqual(array1.validationFunc, array1prime.validationFunc); + + // 1/2/3 shouldn't be equal. + XCTAssertNotEqualObjects(array1, array2); + XCTAssertNotEqualObjects(array1, array3); + XCTAssertNotEqualObjects(array2, array3); + + [array1 release]; + [array1prime release]; + [array2 release]; + [array3 release]; +} + +- (void)testCopy { + const int32_t kValues[] = { 71, 72 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + [array addRawValue:1000]; // Unknown + XCTAssertEqual(array.count, 3U); + XCTAssertEqual([array rawValueAtIndex:0], 71); + XCTAssertEqual([array rawValueAtIndex:1], 72); + XCTAssertEqual([array rawValueAtIndex:2], 1000); + XCTAssertEqual([array valueAtIndex:2], kGPBUnrecognizedEnumeratorValue); + + GPBEnumArray *array2 = [array copy]; + XCTAssertNotNil(array2); + + // Should be new object but equal. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); + XCTAssertEqual(array.validationFunc, array2.validationFunc); + XCTAssertTrue([array2 isKindOfClass:[GPBEnumArray class]]); + XCTAssertEqual(array2.count, 3U); + XCTAssertEqual([array2 rawValueAtIndex:0], 71); + XCTAssertEqual([array2 rawValueAtIndex:1], 72); + XCTAssertEqual([array2 rawValueAtIndex:2], 1000); + XCTAssertEqual([array2 valueAtIndex:2], kGPBUnrecognizedEnumeratorValue); +} + +- (void)testArrayFromArray { + const int32_t kValues[] = { 71, 172, 173, 74 }; // Unknowns + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBEnumArray *array2 = [GPBEnumArray arrayWithValueArray:array]; + XCTAssertNotNil(array2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); + XCTAssertEqual(array.validationFunc, array2.validationFunc); +} + +- (void)testUnknownAdds { + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue]; + XCTAssertNotNil(array); + + XCTAssertThrowsSpecificNamed([array addValue:172], + NSException, NSInvalidArgumentException); + XCTAssertEqual(array.count, 0U); + + const int32_t kValues1[] = { 172, 173 }; // Unknown + XCTAssertThrowsSpecificNamed([array addValues:kValues1 count:GPBARRAYSIZE(kValues1)], + NSException, NSInvalidArgumentException); + XCTAssertEqual(array.count, 0U); + + [array release]; +} + +- (void)testRawAdds { + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue]; + XCTAssertNotNil(array); + + XCTAssertEqual(array.count, 0U); + [array addRawValue:71]; // Valid + XCTAssertEqual(array.count, 1U); + + const int32_t kValues1[] = { 172, 173 }; // Unknown + [array addRawValues:kValues1 count:GPBARRAYSIZE(kValues1)]; + XCTAssertEqual(array.count, 3U); + + const int32_t kValues2[] = { 74, 71 }; + GPBEnumArray *array2 = + [[GPBEnumArray alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + [array addRawValuesFromArray:array2]; + XCTAssertEqual(array.count, 5U); + + XCTAssertEqual([array rawValueAtIndex:0], 71); + XCTAssertEqual([array rawValueAtIndex:1], 172); + XCTAssertEqual([array valueAtIndex:1], kGPBUnrecognizedEnumeratorValue); + XCTAssertEqual([array rawValueAtIndex:2], 173); + XCTAssertEqual([array valueAtIndex:2], kGPBUnrecognizedEnumeratorValue); + XCTAssertEqual([array rawValueAtIndex:3], 74); + XCTAssertEqual([array rawValueAtIndex:4], 71); + + [array release]; +} + +- (void)testUnknownInserts { + const int32_t kValues[] = { 71, 72, 73 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 3U); + + // First + XCTAssertThrowsSpecificNamed([array insertValue:174 atIndex:0], + NSException, NSInvalidArgumentException); + XCTAssertEqual(array.count, 3U); + + // Middle + XCTAssertThrowsSpecificNamed([array insertValue:274 atIndex:1], + NSException, NSInvalidArgumentException); + XCTAssertEqual(array.count, 3U); + + // End + XCTAssertThrowsSpecificNamed([array insertValue:374 atIndex:3], + NSException, NSInvalidArgumentException); + XCTAssertEqual(array.count, 3U); +} + +- (void)testRawInsert { + const int32_t kValues[] = { 71, 72, 73 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 3U); + + // First + [array insertRawValue:174 atIndex:0]; // Unknown + XCTAssertEqual(array.count, 4U); + + // Middle + [array insertRawValue:274 atIndex:2]; // Unknown + XCTAssertEqual(array.count, 5U); + + // End + [array insertRawValue:374 atIndex:5]; // Unknown + XCTAssertEqual(array.count, 6U); + + // Too far. + XCTAssertThrowsSpecificNamed([array insertRawValue:74 atIndex:7], + NSException, NSRangeException); + + XCTAssertEqual([array rawValueAtIndex:0], 174); + XCTAssertEqual([array valueAtIndex:0], kGPBUnrecognizedEnumeratorValue); + XCTAssertEqual([array rawValueAtIndex:1], 71); + XCTAssertEqual([array rawValueAtIndex:2], 274); + XCTAssertEqual([array valueAtIndex:2], kGPBUnrecognizedEnumeratorValue); + XCTAssertEqual([array rawValueAtIndex:3], 72); + XCTAssertEqual([array rawValueAtIndex:4], 73); + XCTAssertEqual([array rawValueAtIndex:5], 374); + XCTAssertEqual([array valueAtIndex:5], kGPBUnrecognizedEnumeratorValue); + + [array release]; +} + +- (void)testUnknownInplaceMutation { + const int32_t kValues[] = { 71, 72, 73, 74 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:1 withValue:172], + NSException, NSInvalidArgumentException); + XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:3 withValue:274], + NSException, NSInvalidArgumentException); + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 71); + XCTAssertEqual([array valueAtIndex:1], 72); + XCTAssertEqual([array valueAtIndex:2], 73); + XCTAssertEqual([array valueAtIndex:3], 74); +} + + +- (void)testRawInplaceMutation { + const int32_t kValues[] = { 71, 72, 73, 74 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + [array replaceValueAtIndex:1 withRawValue:172]; // Unknown + [array replaceValueAtIndex:3 withRawValue:274]; // Unknown + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array rawValueAtIndex:0], 71); + XCTAssertEqual([array rawValueAtIndex:1], 172); + XCTAssertEqual([array valueAtIndex:1], kGPBUnrecognizedEnumeratorValue); + XCTAssertEqual([array rawValueAtIndex:2], 73); + XCTAssertEqual([array rawValueAtIndex:3], 274); + XCTAssertEqual([array valueAtIndex:3], kGPBUnrecognizedEnumeratorValue); + + XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withRawValue:74], + NSException, NSRangeException); +} + +- (void)testRawInternalResizing { + const int32_t kValues[] = { 71, 172, 173, 74 }; // Unknown + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + // Add/remove to trigger the intneral buffer to grow/shrink. + for (int i = 0; i < 100; ++i) { + [array addRawValues:kValues count:GPBARRAYSIZE(kValues)]; + } + XCTAssertEqual(array.count, 404U); + for (int i = 0; i < 100; ++i) { + [array removeValueAtIndex:(i * 2)]; + } + XCTAssertEqual(array.count, 304U); + for (int i = 0; i < 100; ++i) { + [array insertRawValue:274 atIndex:(i * 3)]; // Unknown + } + XCTAssertEqual(array.count, 404U); + [array removeAll]; + XCTAssertEqual(array.count, 0U); +} + +@end diff --git a/objectivec/Tests/GPBCodedInputStreamTests.m b/objectivec/Tests/GPBCodedInputStreamTests.m new file mode 100644 index 00000000..0a709cbe --- /dev/null +++ b/objectivec/Tests/GPBCodedInputStreamTests.m @@ -0,0 +1,290 @@ +// 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. + +#import "GPBTestUtilities.h" + +#import "GPBCodedInputStream.h" +#import "GPBCodedOutputStream.h" +#import "GPBUnknownFieldSet_PackagePrivate.h" +#import "GPBUtilities_PackagePrivate.h" +#import "google/protobuf/Unittest.pbobjc.h" + +@interface CodedInputStreamTests : GPBTestCase +@end + +@implementation CodedInputStreamTests + +- (NSData*)bytes_with_sentinel:(int32_t)unused, ... { + va_list list; + va_start(list, unused); + + NSMutableData* values = [NSMutableData dataWithCapacity:0]; + int32_t i; + + while ((i = va_arg(list, int32_t)) != 256) { + NSAssert(i >= 0 && i < 256, @""); + uint8_t u = (uint8_t)i; + [values appendBytes:&u length:1]; + } + + va_end(list); + + return values; +} + +#define bytes(...) [self bytes_with_sentinel:0, __VA_ARGS__, 256] + +- (void)testDecodeZigZag { + XCTAssertEqual(0, GPBDecodeZigZag32(0)); + XCTAssertEqual(-1, GPBDecodeZigZag32(1)); + XCTAssertEqual(1, GPBDecodeZigZag32(2)); + XCTAssertEqual(-2, GPBDecodeZigZag32(3)); + XCTAssertEqual((int32_t)0x3FFFFFFF, GPBDecodeZigZag32(0x7FFFFFFE)); + XCTAssertEqual((int32_t)0xC0000000, GPBDecodeZigZag32(0x7FFFFFFF)); + XCTAssertEqual((int32_t)0x7FFFFFFF, GPBDecodeZigZag32(0xFFFFFFFE)); + XCTAssertEqual((int32_t)0x80000000, GPBDecodeZigZag32(0xFFFFFFFF)); + + XCTAssertEqual((int64_t)0, GPBDecodeZigZag64(0)); + XCTAssertEqual((int64_t)-1, GPBDecodeZigZag64(1)); + XCTAssertEqual((int64_t)1, GPBDecodeZigZag64(2)); + XCTAssertEqual((int64_t)-2, GPBDecodeZigZag64(3)); + XCTAssertEqual((int64_t)0x000000003FFFFFFFL, + GPBDecodeZigZag64(0x000000007FFFFFFEL)); + XCTAssertEqual((int64_t)0xFFFFFFFFC0000000L, + GPBDecodeZigZag64(0x000000007FFFFFFFL)); + XCTAssertEqual((int64_t)0x000000007FFFFFFFL, + GPBDecodeZigZag64(0x00000000FFFFFFFEL)); + XCTAssertEqual((int64_t)0xFFFFFFFF80000000L, + GPBDecodeZigZag64(0x00000000FFFFFFFFL)); + XCTAssertEqual((int64_t)0x7FFFFFFFFFFFFFFFL, + GPBDecodeZigZag64(0xFFFFFFFFFFFFFFFEL)); + XCTAssertEqual((int64_t)0x8000000000000000L, + GPBDecodeZigZag64(0xFFFFFFFFFFFFFFFFL)); +} + +- (void)assertReadVarint:(NSData*)data value:(int64_t)value { + { + GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data]; + XCTAssertEqual((int32_t)value, [input readInt32]); + } + { + GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data]; + XCTAssertEqual(value, [input readInt64]); + } +} + +- (void)assertReadLittleEndian32:(NSData*)data value:(int32_t)value { + GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data]; + XCTAssertEqual(value, [input readSFixed32]); +} + +- (void)assertReadLittleEndian64:(NSData*)data value:(int64_t)value { + GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data]; + XCTAssertEqual(value, [input readSFixed64]); +} + +- (void)assertReadVarintFailure:(NSData*)data { + { + GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data]; + XCTAssertThrows([input readInt32]); + } + { + GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data]; + XCTAssertThrows([input readInt64]); + } +} + +- (void)testBytes { + NSData* data = bytes(0xa2, 0x74); + XCTAssertEqual(data.length, (NSUInteger)2); + XCTAssertEqual(((uint8_t*)data.bytes)[0], (uint8_t)0xa2); + XCTAssertEqual(((uint8_t*)data.bytes)[1], (uint8_t)0x74); +} + +- (void)testReadVarint { + [self assertReadVarint:bytes(0x00) value:0]; + [self assertReadVarint:bytes(0x01) value:1]; + [self assertReadVarint:bytes(0x7f) value:127]; + // 14882 + [self assertReadVarint:bytes(0xa2, 0x74) value:(0x22 << 0) | (0x74 << 7)]; + // 2961488830 + [self assertReadVarint:bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b) + value:(0x3e << 0) | (0x77 << 7) | (0x12 << 14) | + (0x04 << 21) | (0x0bLL << 28)]; + + // 64-bit + // 7256456126 + [self assertReadVarint:bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b) + value:(0x3e << 0) | (0x77 << 7) | (0x12 << 14) | + (0x04 << 21) | (0x1bLL << 28)]; + // 41256202580718336 + [self assertReadVarint:bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49) + value:(0x00 << 0) | (0x66 << 7) | (0x6b << 14) | + (0x1c << 21) | (0x43LL << 28) | (0x49LL << 35) | + (0x24LL << 42) | (0x49LL << 49)]; + // 11964378330978735131 + [self + assertReadVarint:bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, + 0xa6, 0x01) + value:(0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) | + (0x3bLL << 28) | (0x56LL << 35) | (0x00LL << 42) | + (0x05LL << 49) | (0x26LL << 56) | (0x01LL << 63)]; + + // Failures + [self assertReadVarintFailure:bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x00)]; + [self assertReadVarintFailure:bytes(0x80)]; +} + +- (void)testReadLittleEndian { + [self assertReadLittleEndian32:bytes(0x78, 0x56, 0x34, 0x12) + value:0x12345678]; + [self assertReadLittleEndian32:bytes(0xf0, 0xde, 0xbc, 0x9a) + value:0x9abcdef0]; + + [self assertReadLittleEndian64:bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, + 0x12) + value:0x123456789abcdef0LL]; + [self assertReadLittleEndian64:bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, + 0x9a) + value:0x9abcdef012345678LL]; +} + +- (void)testReadWholeMessage { + TestAllTypes* message = [self allSetRepeatedCount:kGPBDefaultRepeatCount]; + + NSData* rawBytes = message.data; + XCTAssertEqual(message.serializedSize, (size_t)rawBytes.length); + + TestAllTypes* message2 = + [TestAllTypes parseFromData:rawBytes extensionRegistry:nil]; + [self assertAllFieldsSet:message2 repeatedCount:kGPBDefaultRepeatCount]; +} + +- (void)testSkipWholeMessage { + TestAllTypes* message = [self allSetRepeatedCount:kGPBDefaultRepeatCount]; + NSData* rawBytes = message.data; + + // Create two parallel inputs. Parse one as unknown fields while using + // skipField() to skip each field on the other. Expect the same tags. + GPBCodedInputStream* input1 = [GPBCodedInputStream streamWithData:rawBytes]; + GPBCodedInputStream* input2 = [GPBCodedInputStream streamWithData:rawBytes]; + GPBUnknownFieldSet* unknownFields = + [[[GPBUnknownFieldSet alloc] init] autorelease]; + + while (YES) { + int32_t tag = [input1 readTag]; + XCTAssertEqual(tag, [input2 readTag]); + if (tag == 0) { + break; + } + [unknownFields mergeFieldFrom:tag input:input1]; + [input2 skipField:tag]; + } +} + +- (void)testReadHugeBlob { + // Allocate and initialize a 1MB blob. + NSMutableData* blob = [NSMutableData dataWithLength:1 << 20]; + for (NSUInteger i = 0; i < blob.length; i++) { + ((uint8_t*)blob.mutableBytes)[i] = (uint8_t)i; + } + + // Make a message containing it. + TestAllTypes* message = [TestAllTypes message]; + [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount]; + [message setOptionalBytes:blob]; + + // Serialize and parse it. Make sure to parse from an InputStream, not + // directly from a ByteString, so that CodedInputStream uses buffered + // reading. + GPBCodedInputStream* stream = + [GPBCodedInputStream streamWithData:message.data]; + TestAllTypes* message2 = + [TestAllTypes parseFromCodedInputStream:stream extensionRegistry:nil]; + + XCTAssertEqualObjects(message.optionalBytes, message2.optionalBytes); + + // Make sure all the other fields were parsed correctly. + TestAllTypes* message3 = [[message2 copy] autorelease]; + TestAllTypes* types = [self allSetRepeatedCount:kGPBDefaultRepeatCount]; + NSData* data = [types optionalBytes]; + [message3 setOptionalBytes:data]; + + [self assertAllFieldsSet:message3 repeatedCount:kGPBDefaultRepeatCount]; +} + +- (void)testReadMaliciouslyLargeBlob { + NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory]; + GPBCodedOutputStream* output = + [GPBCodedOutputStream streamWithOutputStream:rawOutput]; + + int32_t tag = GPBWireFormatMakeTag(1, GPBWireFormatLengthDelimited); + [output writeRawVarint32:tag]; + [output writeRawVarint32:0x7FFFFFFF]; + uint8_t bytes[32] = {0}; + [output writeRawData:[NSData dataWithBytes:bytes length:32]]; + [output flush]; + + NSData* data = + [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + GPBCodedInputStream* input = + [GPBCodedInputStream streamWithData:[NSMutableData dataWithData:data]]; + XCTAssertEqual(tag, [input readTag]); + + XCTAssertThrows([input readData]); +} + +// Verifies fix for b/10315336. +- (void)testReadMalformedString { + NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory]; + GPBCodedOutputStream* output = + [GPBCodedOutputStream streamWithOutputStream:rawOutput]; + + int32_t tag = GPBWireFormatMakeTag(TestAllTypes_FieldNumber_DefaultString, + GPBWireFormatLengthDelimited); + [output writeRawVarint32:tag]; + [output writeRawVarint32:5]; + // Create an invalid utf-8 byte array. + uint8_t bytes[5] = {0xc2, 0xf2}; + [output writeRawData:[NSData dataWithBytes:bytes length:sizeof(bytes)]]; + [output flush]; + + NSData* data = + [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data]; + TestAllTypes* message = + [TestAllTypes parseFromCodedInputStream:input extensionRegistry:nil]; + // Make sure we can read string properties twice without crashing. + XCTAssertEqual([message.defaultString length], (NSUInteger)0); + XCTAssertEqualObjects(@"", message.defaultString); +} + +@end diff --git a/objectivec/Tests/GPBCodedOuputStreamTests.m b/objectivec/Tests/GPBCodedOuputStreamTests.m new file mode 100644 index 00000000..77d88033 --- /dev/null +++ b/objectivec/Tests/GPBCodedOuputStreamTests.m @@ -0,0 +1,321 @@ +// 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. + +#import "GPBTestUtilities.h" + +#import "GPBCodedOutputStream.h" +#import "GPBCodedInputStream.h" +#import "GPBUtilities_PackagePrivate.h" +#import "google/protobuf/Unittest.pbobjc.h" + +@interface CodedOutputStreamTests : GPBTestCase +@end + +@implementation CodedOutputStreamTests + +- (NSData*)bytes_with_sentinel:(int32_t)unused, ... { + va_list list; + va_start(list, unused); + + NSMutableData* values = [NSMutableData dataWithCapacity:0]; + int32_t i; + + while ((i = va_arg(list, int32_t)) != 256) { + NSAssert(i >= 0 && i < 256, @""); + uint8_t u = (uint8_t)i; + [values appendBytes:&u length:1]; + } + + va_end(list); + + return values; +} + +#define bytes(...) [self bytes_with_sentinel:0, __VA_ARGS__, 256] + +- (void)assertWriteLittleEndian32:(NSData*)data value:(int32_t)value { + NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory]; + GPBCodedOutputStream* output = + [GPBCodedOutputStream streamWithOutputStream:rawOutput]; + [output writeRawLittleEndian32:(int32_t)value]; + [output flush]; + + NSData* actual = + [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + XCTAssertEqualObjects(data, actual); + + // Try different block sizes. + for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { + rawOutput = [NSOutputStream outputStreamToMemory]; + output = [GPBCodedOutputStream streamWithOutputStream:rawOutput + bufferSize:blockSize]; + [output writeRawLittleEndian32:(int32_t)value]; + [output flush]; + + actual = [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + XCTAssertEqualObjects(data, actual); + } +} + +- (void)assertWriteLittleEndian64:(NSData*)data value:(int64_t)value { + NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory]; + GPBCodedOutputStream* output = + [GPBCodedOutputStream streamWithOutputStream:rawOutput]; + [output writeRawLittleEndian64:value]; + [output flush]; + + NSData* actual = + [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + XCTAssertEqualObjects(data, actual); + + // Try different block sizes. + for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { + rawOutput = [NSOutputStream outputStreamToMemory]; + output = [GPBCodedOutputStream streamWithOutputStream:rawOutput + bufferSize:blockSize]; + [output writeRawLittleEndian64:value]; + [output flush]; + + actual = [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + XCTAssertEqualObjects(data, actual); + } +} + +- (void)assertWriteVarint:(NSData*)data value:(int64_t)value { + // Only do 32-bit write if the value fits in 32 bits. + if (GPBLogicalRightShift64(value, 32) == 0) { + NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory]; + GPBCodedOutputStream* output = + [GPBCodedOutputStream streamWithOutputStream:rawOutput]; + [output writeRawVarint32:(int32_t)value]; + [output flush]; + + NSData* actual = + [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + XCTAssertEqualObjects(data, actual); + + // Also try computing size. + XCTAssertEqual(GPBComputeRawVarint32Size((int32_t)value), + (size_t)data.length); + } + + { + NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory]; + GPBCodedOutputStream* output = + [GPBCodedOutputStream streamWithOutputStream:rawOutput]; + [output writeRawVarint64:value]; + [output flush]; + + NSData* actual = + [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + XCTAssertEqualObjects(data, actual); + + // Also try computing size. + XCTAssertEqual(GPBComputeRawVarint64Size(value), (size_t)data.length); + } + + // Try different block sizes. + for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { + // Only do 32-bit write if the value fits in 32 bits. + if (GPBLogicalRightShift64(value, 32) == 0) { + NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory]; + GPBCodedOutputStream* output = + [GPBCodedOutputStream streamWithOutputStream:rawOutput + bufferSize:blockSize]; + + [output writeRawVarint32:(int32_t)value]; + [output flush]; + + NSData* actual = + [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + XCTAssertEqualObjects(data, actual); + } + + { + NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory]; + GPBCodedOutputStream* output = + [GPBCodedOutputStream streamWithOutputStream:rawOutput + bufferSize:blockSize]; + + [output writeRawVarint64:value]; + [output flush]; + + NSData* actual = + [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + XCTAssertEqualObjects(data, actual); + } + } +} + +- (void)testWriteVarint1 { + [self assertWriteVarint:bytes(0x00) value:0]; +} + +- (void)testWriteVarint2 { + [self assertWriteVarint:bytes(0x01) value:1]; +} + +- (void)testWriteVarint3 { + [self assertWriteVarint:bytes(0x7f) value:127]; +} + +- (void)testWriteVarint4 { + // 14882 + [self assertWriteVarint:bytes(0xa2, 0x74) value:(0x22 << 0) | (0x74 << 7)]; +} + +- (void)testWriteVarint5 { + // 2961488830 + [self assertWriteVarint:bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b) + value:(0x3e << 0) | (0x77 << 7) | (0x12 << 14) | + (0x04 << 21) | (0x0bLL << 28)]; +} + +- (void)testWriteVarint6 { + // 64-bit + // 7256456126 + [self assertWriteVarint:bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b) + value:(0x3e << 0) | (0x77 << 7) | (0x12 << 14) | + (0x04 << 21) | (0x1bLL << 28)]; +} + +- (void)testWriteVarint7 { + // 41256202580718336 + [self assertWriteVarint:bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49) + value:(0x00 << 0) | (0x66 << 7) | (0x6b << 14) | + (0x1c << 21) | (0x43LL << 28) | (0x49LL << 35) | + (0x24LL << 42) | (0x49LL << 49)]; +} + +- (void)testWriteVarint8 { + // 11964378330978735131 + [self assertWriteVarint:bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, + 0xa6, 0x01) + value:(0x1b << 0) | (0x28 << 7) | (0x79 << 14) | + (0x42 << 21) | (0x3bLL << 28) | (0x56LL << 35) | + (0x00LL << 42) | (0x05LL << 49) | (0x26LL << 56) | + (0x01LL << 63)]; +} + +- (void)testWriteLittleEndian { + [self assertWriteLittleEndian32:bytes(0x78, 0x56, 0x34, 0x12) + value:0x12345678]; + [self assertWriteLittleEndian32:bytes(0xf0, 0xde, 0xbc, 0x9a) + value:0x9abcdef0]; + + [self assertWriteLittleEndian64:bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, + 0x34, 0x12) + value:0x123456789abcdef0LL]; + [self assertWriteLittleEndian64:bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, + 0xbc, 0x9a) + value:0x9abcdef012345678LL]; +} + +- (void)testEncodeZigZag { + XCTAssertEqual(0U, GPBEncodeZigZag32(0)); + XCTAssertEqual(1U, GPBEncodeZigZag32(-1)); + XCTAssertEqual(2U, GPBEncodeZigZag32(1)); + XCTAssertEqual(3U, GPBEncodeZigZag32(-2)); + XCTAssertEqual(0x7FFFFFFEU, GPBEncodeZigZag32(0x3FFFFFFF)); + XCTAssertEqual(0x7FFFFFFFU, GPBEncodeZigZag32(0xC0000000)); + XCTAssertEqual(0xFFFFFFFEU, GPBEncodeZigZag32(0x7FFFFFFF)); + XCTAssertEqual(0xFFFFFFFFU, GPBEncodeZigZag32(0x80000000)); + + XCTAssertEqual(0ULL, GPBEncodeZigZag64(0)); + XCTAssertEqual(1ULL, GPBEncodeZigZag64(-1)); + XCTAssertEqual(2ULL, GPBEncodeZigZag64(1)); + XCTAssertEqual(3ULL, GPBEncodeZigZag64(-2)); + XCTAssertEqual(0x000000007FFFFFFEULL, + GPBEncodeZigZag64(0x000000003FFFFFFFLL)); + XCTAssertEqual(0x000000007FFFFFFFULL, + GPBEncodeZigZag64(0xFFFFFFFFC0000000LL)); + XCTAssertEqual(0x00000000FFFFFFFEULL, + GPBEncodeZigZag64(0x000000007FFFFFFFLL)); + XCTAssertEqual(0x00000000FFFFFFFFULL, + GPBEncodeZigZag64(0xFFFFFFFF80000000LL)); + XCTAssertEqual(0xFFFFFFFFFFFFFFFEULL, + GPBEncodeZigZag64(0x7FFFFFFFFFFFFFFFLL)); + XCTAssertEqual(0xFFFFFFFFFFFFFFFFULL, + GPBEncodeZigZag64(0x8000000000000000LL)); + + // Some easier-to-verify round-trip tests. The inputs (other than 0, 1, -1) + // were chosen semi-randomly via keyboard bashing. + XCTAssertEqual(0U, GPBEncodeZigZag32(GPBDecodeZigZag32(0))); + XCTAssertEqual(1U, GPBEncodeZigZag32(GPBDecodeZigZag32(1))); + XCTAssertEqual(-1U, GPBEncodeZigZag32(GPBDecodeZigZag32(-1))); + XCTAssertEqual(14927U, GPBEncodeZigZag32(GPBDecodeZigZag32(14927))); + XCTAssertEqual(-3612U, GPBEncodeZigZag32(GPBDecodeZigZag32(-3612))); + + XCTAssertEqual(0ULL, GPBEncodeZigZag64(GPBDecodeZigZag64(0))); + XCTAssertEqual(1ULL, GPBEncodeZigZag64(GPBDecodeZigZag64(1))); + XCTAssertEqual(-1ULL, GPBEncodeZigZag64(GPBDecodeZigZag64(-1))); + XCTAssertEqual(14927ULL, GPBEncodeZigZag64(GPBDecodeZigZag64(14927))); + XCTAssertEqual(-3612ULL, GPBEncodeZigZag64(GPBDecodeZigZag64(-3612))); + + XCTAssertEqual(856912304801416ULL, + GPBEncodeZigZag64(GPBDecodeZigZag64(856912304801416LL))); + XCTAssertEqual(-75123905439571256ULL, + GPBEncodeZigZag64(GPBDecodeZigZag64(-75123905439571256LL))); +} + +- (void)testWriteWholeMessage { + // Not kGPBDefaultRepeatCount because we are comparing to a golden master file + // that was generated with 2. + TestAllTypes* message = [self allSetRepeatedCount:2]; + + NSData* rawBytes = message.data; + NSData* goldenData = + [self getDataFileNamed:@"golden_message" dataToWrite:rawBytes]; + XCTAssertEqualObjects(rawBytes, goldenData); + + // Try different block sizes. + for (int blockSize = 1; blockSize < 256; blockSize *= 2) { + NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory]; + GPBCodedOutputStream* output = + [GPBCodedOutputStream streamWithOutputStream:rawOutput + bufferSize:blockSize]; + [message writeToCodedOutputStream:output]; + [output flush]; + + NSData* actual = + [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + XCTAssertEqualObjects(rawBytes, actual); + } + + // Not kGPBDefaultRepeatCount because we are comparing to a golden master file + // that was generated with 2. + TestAllExtensions* extensions = [self allExtensionsSetRepeatedCount:2]; + rawBytes = extensions.data; + goldenData = [self getDataFileNamed:@"golden_packed_fields_message" + dataToWrite:rawBytes]; + XCTAssertEqualObjects(rawBytes, goldenData); +} + +@end diff --git a/objectivec/Tests/GPBConcurrencyTests.m b/objectivec/Tests/GPBConcurrencyTests.m new file mode 100644 index 00000000..3749fc34 --- /dev/null +++ b/objectivec/Tests/GPBConcurrencyTests.m @@ -0,0 +1,157 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 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. + +#import "GPBTestUtilities.h" + +#import "google/protobuf/Unittest.pbobjc.h" + +static const int kNumThreads = 100; +static const int kNumMessages = 100; + +@interface ConcurrencyTests : GPBTestCase +@end + +@implementation ConcurrencyTests + +- (NSArray *)createThreadsWithSelector:(SEL)selector object:(id)object { + NSMutableArray *array = [NSMutableArray array]; + for (NSUInteger i = 0; i < kNumThreads; i++) { + NSThread *thread = + [[NSThread alloc] initWithTarget:self selector:selector object:object]; + [array addObject:thread]; + [thread release]; + } + return array; +} + +- (NSArray *)createMessagesWithType:(Class)msgType { + NSMutableArray *array = [NSMutableArray array]; + for (NSUInteger i = 0; i < kNumMessages; i++) { + [array addObject:[msgType message]]; + } + return array; +} + +- (void)startThreads:(NSArray *)threads { + for (NSThread *thread in threads) { + [thread start]; + } +} + +- (void)joinThreads:(NSArray *)threads { + for (NSThread *thread in threads) { + while (![thread isFinished]) + ; + } +} + +- (void)readForeignMessage:(NSArray *)messages { + for (NSUInteger i = 0; i < 10; i++) { + for (TestAllTypes *message in messages) { + XCTAssertEqual(message.optionalForeignMessage.c, 0); + } + } +} + +- (void)testConcurrentReadOfUnsetMessageField { + NSArray *messages = [self createMessagesWithType:[TestAllTypes class]]; + NSArray *threads = + [self createThreadsWithSelector:@selector(readForeignMessage:) + object:messages]; + [self startThreads:threads]; + [self joinThreads:threads]; + for (TestAllTypes *message in messages) { + XCTAssertFalse(message.hasOptionalForeignMessage); + } +} + +- (void)readRepeatedInt32:(NSArray *)messages { + for (int i = 0; i < 10; i++) { + for (TestAllTypes *message in messages) { + XCTAssertEqual([message.repeatedInt32Array count], (NSUInteger)0); + } + } +} + +- (void)testConcurrentReadOfUnsetRepeatedIntField { + NSArray *messages = [self createMessagesWithType:[TestAllTypes class]]; + NSArray *threads = + [self createThreadsWithSelector:@selector(readRepeatedInt32:) + object:messages]; + [self startThreads:threads]; + [self joinThreads:threads]; + for (TestAllTypes *message in messages) { + XCTAssertEqual([message.repeatedInt32Array count], (NSUInteger)0); + } +} + +- (void)readRepeatedString:(NSArray *)messages { + for (int i = 0; i < 10; i++) { + for (TestAllTypes *message in messages) { + XCTAssertEqual([message.repeatedStringArray count], (NSUInteger)0); + } + } +} + +- (void)testConcurrentReadOfUnsetRepeatedStringField { + NSArray *messages = [self createMessagesWithType:[TestAllTypes class]]; + NSArray *threads = + [self createThreadsWithSelector:@selector(readRepeatedString:) + object:messages]; + [self startThreads:threads]; + [self joinThreads:threads]; + for (TestAllTypes *message in messages) { + XCTAssertEqual([message.repeatedStringArray count], (NSUInteger)0); + } +} + +- (void)readOptionalForeignMessageExtension:(NSArray *)messages { + for (int i = 0; i < 10; i++) { + for (TestAllExtensions *message in messages) { + ForeignMessage *foreign = + [message getExtension:[UnittestRoot optionalForeignMessageExtension]]; + XCTAssertEqual(foreign.c, 0); + } + } +} + +- (void)testConcurrentReadOfUnsetExtensionField { + NSArray *messages = [self createMessagesWithType:[TestAllExtensions class]]; + SEL sel = @selector(readOptionalForeignMessageExtension:); + NSArray *threads = [self createThreadsWithSelector:sel object:messages]; + [self startThreads:threads]; + [self joinThreads:threads]; + GPBExtensionField *extension = [UnittestRoot optionalForeignMessageExtension]; + for (TestAllExtensions *message in messages) { + XCTAssertFalse([message hasExtension:extension]); + } +} + +@end diff --git a/objectivec/Tests/GPBDescriptorTests.m b/objectivec/Tests/GPBDescriptorTests.m new file mode 100644 index 00000000..ccdbb645 --- /dev/null +++ b/objectivec/Tests/GPBDescriptorTests.m @@ -0,0 +1,232 @@ +// 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. + +#import "GPBTestUtilities.h" + +#import <objc/runtime.h> + +#import "GPBDescriptor.h" +#import "google/protobuf/Unittest.pbobjc.h" + +@interface DescriptorTests : GPBTestCase +@end + +@implementation DescriptorTests + +- (void)testFieldDescriptor { + GPBDescriptor *descriptor = [TestAllTypes descriptor]; + + // Nested Enum + GPBFieldDescriptor *fieldDescriptorWithName = + [descriptor fieldWithName:@"optionalNestedEnum"]; + XCTAssertNotNil(fieldDescriptorWithName); + GPBFieldDescriptor *fieldDescriptorWithNumber = + [descriptor fieldWithNumber:21]; + XCTAssertNotNil(fieldDescriptorWithNumber); + XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber); + XCTAssertNotNil(fieldDescriptorWithNumber.enumDescriptor); + XCTAssertEqualObjects(fieldDescriptorWithNumber.enumDescriptor.name, + @"TestAllTypes_NestedEnum"); + + // Foreign Enum + fieldDescriptorWithName = [descriptor fieldWithName:@"optionalForeignEnum"]; + XCTAssertNotNil(fieldDescriptorWithName); + fieldDescriptorWithNumber = [descriptor fieldWithNumber:22]; + XCTAssertNotNil(fieldDescriptorWithNumber); + XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber); + XCTAssertNotNil(fieldDescriptorWithNumber.enumDescriptor); + XCTAssertEqualObjects(fieldDescriptorWithNumber.enumDescriptor.name, + @"ForeignEnum"); + + // Import Enum + fieldDescriptorWithName = [descriptor fieldWithName:@"optionalImportEnum"]; + XCTAssertNotNil(fieldDescriptorWithName); + fieldDescriptorWithNumber = [descriptor fieldWithNumber:23]; + XCTAssertNotNil(fieldDescriptorWithNumber); + XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber); + XCTAssertNotNil(fieldDescriptorWithNumber.enumDescriptor); + XCTAssertEqualObjects(fieldDescriptorWithNumber.enumDescriptor.name, + @"ImportEnum"); + + // Nested Message + fieldDescriptorWithName = [descriptor fieldWithName:@"optionalNestedMessage"]; + XCTAssertNotNil(fieldDescriptorWithName); + fieldDescriptorWithNumber = [descriptor fieldWithNumber:18]; + XCTAssertNotNil(fieldDescriptorWithNumber); + XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber); + XCTAssertNil(fieldDescriptorWithNumber.enumDescriptor); + + // Foreign Message + fieldDescriptorWithName = + [descriptor fieldWithName:@"optionalForeignMessage"]; + XCTAssertNotNil(fieldDescriptorWithName); + fieldDescriptorWithNumber = [descriptor fieldWithNumber:19]; + XCTAssertNotNil(fieldDescriptorWithNumber); + XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber); + XCTAssertNil(fieldDescriptorWithNumber.enumDescriptor); + + // Import Message + fieldDescriptorWithName = [descriptor fieldWithName:@"optionalImportMessage"]; + XCTAssertNotNil(fieldDescriptorWithName); + fieldDescriptorWithNumber = [descriptor fieldWithNumber:20]; + XCTAssertNotNil(fieldDescriptorWithNumber); + XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber); + XCTAssertNil(fieldDescriptorWithNumber.enumDescriptor); +} + +- (void)testEnumDescriptor { + GPBEnumDescriptor *descriptor = TestAllTypes_NestedEnum_EnumDescriptor(); + + NSString *enumName = [descriptor enumNameForValue:1]; + XCTAssertNotNil(enumName); + int32_t value; + XCTAssertTrue( + [descriptor getValue:&value forEnumName:@"TestAllTypes_NestedEnum_Foo"]); + XCTAssertTrue( + [descriptor getValue:NULL forEnumName:@"TestAllTypes_NestedEnum_Foo"]); + XCTAssertEqual(value, TestAllTypes_NestedEnum_Foo); + + enumName = [descriptor enumNameForValue:2]; + XCTAssertNotNil(enumName); + XCTAssertTrue( + [descriptor getValue:&value forEnumName:@"TestAllTypes_NestedEnum_Bar"]); + XCTAssertEqual(value, TestAllTypes_NestedEnum_Bar); + + enumName = [descriptor enumNameForValue:3]; + XCTAssertNotNil(enumName); + XCTAssertTrue( + [descriptor getValue:&value forEnumName:@"TestAllTypes_NestedEnum_Baz"]); + XCTAssertEqual(value, TestAllTypes_NestedEnum_Baz); + + // Bad values + enumName = [descriptor enumNameForValue:0]; + XCTAssertNil(enumName); + XCTAssertFalse([descriptor getValue:&value forEnumName:@"Unknown"]); + XCTAssertFalse([descriptor getValue:NULL forEnumName:@"Unknown"]); + XCTAssertFalse([descriptor getValue:&value + forEnumName:@"TestAllTypes_NestedEnum_Unknown"]); + XCTAssertFalse([descriptor getValue:NULL + forEnumName:@"TestAllTypes_NestedEnum_Unknown"]); +} + +- (void)testEnumValueValidator { + GPBDescriptor *descriptor = [TestAllTypes descriptor]; + GPBFieldDescriptor *fieldDescriptor = + [descriptor fieldWithName:@"optionalNestedEnum"]; + + // Valid values + XCTAssertTrue([fieldDescriptor isValidEnumValue:1]); + XCTAssertTrue([fieldDescriptor isValidEnumValue:2]); + XCTAssertTrue([fieldDescriptor isValidEnumValue:3]); + XCTAssertTrue([fieldDescriptor isValidEnumValue:-1]); + + // Invalid values + XCTAssertFalse([fieldDescriptor isValidEnumValue:4]); + XCTAssertFalse([fieldDescriptor isValidEnumValue:0]); + XCTAssertFalse([fieldDescriptor isValidEnumValue:-2]); +} + +- (void)testEnumDescriptorLookup { + GPBDescriptor *descriptor = [TestAllTypes descriptor]; + GPBEnumDescriptor *enumDescriptor = + [descriptor enumWithName:@"TestAllTypes_NestedEnum"]; + XCTAssertNotNil(enumDescriptor); + + // Descriptor cannot find foreign or imported enums. + enumDescriptor = [descriptor enumWithName:@"ForeignEnumEnum"]; + XCTAssertNil(enumDescriptor); + enumDescriptor = [descriptor enumWithName:@"ImportEnumEnum"]; + XCTAssertNil(enumDescriptor); +} + +- (void)testOneofDescriptor { + GPBDescriptor *descriptor = [TestOneof2 descriptor]; + + // All fields should be listed. + XCTAssertEqual(descriptor.fields.count, 17U); + + // There are two oneofs in there. + XCTAssertEqual(descriptor.oneofs.count, 2U); + + GPBFieldDescriptor *fooStringField = + [descriptor fieldWithNumber:TestOneof2_FieldNumber_FooString]; + XCTAssertNotNil(fooStringField); + GPBFieldDescriptor *barStringField = + [descriptor fieldWithNumber:TestOneof2_FieldNumber_BarString]; + XCTAssertNotNil(barStringField); + + // Check the oneofs to have what is expected. + + GPBOneofDescriptor *oneofFoo = [descriptor oneofWithName:@"foo"]; + XCTAssertNotNil(oneofFoo); + XCTAssertEqual(oneofFoo.fields.count, 9U); + + // Pointer comparisons. + XCTAssertEqual([oneofFoo fieldWithNumber:TestOneof2_FieldNumber_FooString], + fooStringField); + XCTAssertEqual([oneofFoo fieldWithName:@"fooString"], fooStringField); + + GPBOneofDescriptor *oneofBar = [descriptor oneofWithName:@"bar"]; + XCTAssertNotNil(oneofBar); + XCTAssertEqual(oneofBar.fields.count, 6U); + + // Pointer comparisons. + XCTAssertEqual([oneofBar fieldWithNumber:TestOneof2_FieldNumber_BarString], + barStringField); + XCTAssertEqual([oneofBar fieldWithName:@"barString"], barStringField); + + // Unknown oneof not found. + + XCTAssertNil([descriptor oneofWithName:@"mumble"]); + XCTAssertNil([descriptor oneofWithName:@"Foo"]); + + // Unknown oneof item. + + XCTAssertNil([oneofFoo fieldWithName:@"mumble"]); + XCTAssertNil([oneofFoo fieldWithNumber:666]); + + // Field exists, but not in this oneof. + + XCTAssertNil([oneofFoo fieldWithName:@"barString"]); + XCTAssertNil([oneofFoo fieldWithNumber:TestOneof2_FieldNumber_BarString]); + XCTAssertNil([oneofBar fieldWithName:@"fooString"]); + XCTAssertNil([oneofBar fieldWithNumber:TestOneof2_FieldNumber_FooString]); + + // Check pointers back to the enclosing oneofs. + // (pointer comparisions) + XCTAssertEqual(fooStringField.containingOneof, oneofFoo); + XCTAssertEqual(barStringField.containingOneof, oneofBar); + GPBFieldDescriptor *bazString = + [descriptor fieldWithNumber:TestOneof2_FieldNumber_BazString]; + XCTAssertNotNil(bazString); + XCTAssertNil(bazString.containingOneof); +} + +@end diff --git a/objectivec/Tests/GPBDictionaryTests+Bool.m b/objectivec/Tests/GPBDictionaryTests+Bool.m new file mode 100644 index 00000000..bc4998be --- /dev/null +++ b/objectivec/Tests/GPBDictionaryTests+Bool.m @@ -0,0 +1,2421 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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. + +#import <Foundation/Foundation.h> +#import <XCTest/XCTest.h> + +#import "GPBDictionary.h" + +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h" + +#ifndef GPBARRAYSIZE +#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0])))) +#endif // GPBARRAYSIZE + +// Pull in the macros (using an external file because expanding all tests +// in a single file makes a file that is failing to work with within Xcode. +//%PDDM-IMPORT-DEFINES GPBDictionaryTests.pddm + +//%PDDM-EXPAND BOOL_TESTS_FOR_POD_VALUE(UInt32, uint32_t, 100U, 101U) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> UInt32 + +@interface GPBBoolUInt32DictionaryTests : XCTestCase +@end + +@implementation GPBBoolUInt32DictionaryTests + +- (void)testEmpty { + GPBBoolUInt32Dictionary *dict = [[GPBBoolUInt32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBBoolUInt32Dictionary *dict = [GPBBoolUInt32Dictionary dictionaryWithValue:100U forKey:YES]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint32_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, YES); + XCTAssertEqual(aValue, 100U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const BOOL kKeys[] = { YES, NO }; + const uint32_t kValues[] = { 100U, 101U }; + GPBBoolUInt32Dictionary *dict = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + uint32_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 101U); + + __block NSUInteger idx = 0; + BOOL *seenKeys = malloc(2 * sizeof(BOOL)); + uint32_t *seenValues = malloc(2 * sizeof(uint32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 2U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 2; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 2) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 0) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const BOOL kKeys1[] = { YES, NO }; + const BOOL kKeys2[] = { NO, YES }; + const uint32_t kValues1[] = { 100U, 101U }; + const uint32_t kValues2[] = { 101U, 100U }; + const uint32_t kValues3[] = { 101U }; + GPBBoolUInt32Dictionary *dict1 = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBBoolUInt32Dictionary *dict1prime = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBBoolUInt32Dictionary *dict2 = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBBoolUInt32Dictionary *dict3 = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBBoolUInt32Dictionary *dict4 = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 Fewer pairs; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const BOOL kKeys[] = { YES, NO }; + const uint32_t kValues[] = { 100U, 101U }; + GPBBoolUInt32Dictionary *dict = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolUInt32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBBoolUInt32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const BOOL kKeys[] = { YES, NO }; + const uint32_t kValues[] = { 100U, 101U }; + GPBBoolUInt32Dictionary *dict = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolUInt32Dictionary *dict2 = + [GPBBoolUInt32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBBoolUInt32Dictionary *dict = [GPBBoolUInt32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:100U forKey:YES]; + XCTAssertEqual(dict.count, 1U); + + const BOOL kKeys[] = { NO }; + const uint32_t kValues[] = { 101U }; + GPBBoolUInt32Dictionary *dict2 = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + + uint32_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 101U); + [dict2 release]; +} + +- (void)testRemove { + const BOOL kKeys[] = { YES, NO}; + const uint32_t kValues[] = { 100U, 101U }; + GPBBoolUInt32Dictionary *dict = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + uint32_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + // Remove again does nothing. + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const BOOL kKeys[] = { YES, NO }; + const uint32_t kValues[] = { 100U, 101U }; + GPBBoolUInt32Dictionary *dict = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + uint32_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 101U); + + [dict setValue:101U forKey:YES]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 101U); + + [dict setValue:100U forKey:NO]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 100U); + + const BOOL kKeys2[] = { NO, YES }; + const uint32_t kValues2[] = { 101U, 100U }; + GPBBoolUInt32Dictionary *dict2 = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 101U); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND BOOL_TESTS_FOR_POD_VALUE(Int32, int32_t, 200, 201) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> Int32 + +@interface GPBBoolInt32DictionaryTests : XCTestCase +@end + +@implementation GPBBoolInt32DictionaryTests + +- (void)testEmpty { + GPBBoolInt32Dictionary *dict = [[GPBBoolInt32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBBoolInt32Dictionary *dict = [GPBBoolInt32Dictionary dictionaryWithValue:200 forKey:YES]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, YES); + XCTAssertEqual(aValue, 200); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const BOOL kKeys[] = { YES, NO }; + const int32_t kValues[] = { 200, 201 }; + GPBBoolInt32Dictionary *dict = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + int32_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 201); + + __block NSUInteger idx = 0; + BOOL *seenKeys = malloc(2 * sizeof(BOOL)); + int32_t *seenValues = malloc(2 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 2U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 2; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 2) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 0) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const BOOL kKeys1[] = { YES, NO }; + const BOOL kKeys2[] = { NO, YES }; + const int32_t kValues1[] = { 200, 201 }; + const int32_t kValues2[] = { 201, 200 }; + const int32_t kValues3[] = { 201 }; + GPBBoolInt32Dictionary *dict1 = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBBoolInt32Dictionary *dict1prime = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBBoolInt32Dictionary *dict2 = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBBoolInt32Dictionary *dict3 = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBBoolInt32Dictionary *dict4 = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 Fewer pairs; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const BOOL kKeys[] = { YES, NO }; + const int32_t kValues[] = { 200, 201 }; + GPBBoolInt32Dictionary *dict = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolInt32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBBoolInt32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const BOOL kKeys[] = { YES, NO }; + const int32_t kValues[] = { 200, 201 }; + GPBBoolInt32Dictionary *dict = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolInt32Dictionary *dict2 = + [GPBBoolInt32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBBoolInt32Dictionary *dict = [GPBBoolInt32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:200 forKey:YES]; + XCTAssertEqual(dict.count, 1U); + + const BOOL kKeys[] = { NO }; + const int32_t kValues[] = { 201 }; + GPBBoolInt32Dictionary *dict2 = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + + int32_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 201); + [dict2 release]; +} + +- (void)testRemove { + const BOOL kKeys[] = { YES, NO}; + const int32_t kValues[] = { 200, 201 }; + GPBBoolInt32Dictionary *dict = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + // Remove again does nothing. + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const BOOL kKeys[] = { YES, NO }; + const int32_t kValues[] = { 200, 201 }; + GPBBoolInt32Dictionary *dict = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + int32_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 201); + + [dict setValue:201 forKey:YES]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 201); + + [dict setValue:200 forKey:NO]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 200); + + const BOOL kKeys2[] = { NO, YES }; + const int32_t kValues2[] = { 201, 200 }; + GPBBoolInt32Dictionary *dict2 = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 201); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND BOOL_TESTS_FOR_POD_VALUE(UInt64, uint64_t, 300U, 301U) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> UInt64 + +@interface GPBBoolUInt64DictionaryTests : XCTestCase +@end + +@implementation GPBBoolUInt64DictionaryTests + +- (void)testEmpty { + GPBBoolUInt64Dictionary *dict = [[GPBBoolUInt64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBBoolUInt64Dictionary *dict = [GPBBoolUInt64Dictionary dictionaryWithValue:300U forKey:YES]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint64_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint64_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, YES); + XCTAssertEqual(aValue, 300U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const BOOL kKeys[] = { YES, NO }; + const uint64_t kValues[] = { 300U, 301U }; + GPBBoolUInt64Dictionary *dict = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + uint64_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 301U); + + __block NSUInteger idx = 0; + BOOL *seenKeys = malloc(2 * sizeof(BOOL)); + uint64_t *seenValues = malloc(2 * sizeof(uint64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 2U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 2; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 2) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 0) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const BOOL kKeys1[] = { YES, NO }; + const BOOL kKeys2[] = { NO, YES }; + const uint64_t kValues1[] = { 300U, 301U }; + const uint64_t kValues2[] = { 301U, 300U }; + const uint64_t kValues3[] = { 301U }; + GPBBoolUInt64Dictionary *dict1 = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBBoolUInt64Dictionary *dict1prime = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBBoolUInt64Dictionary *dict2 = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBBoolUInt64Dictionary *dict3 = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBBoolUInt64Dictionary *dict4 = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 Fewer pairs; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const BOOL kKeys[] = { YES, NO }; + const uint64_t kValues[] = { 300U, 301U }; + GPBBoolUInt64Dictionary *dict = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolUInt64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBBoolUInt64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const BOOL kKeys[] = { YES, NO }; + const uint64_t kValues[] = { 300U, 301U }; + GPBBoolUInt64Dictionary *dict = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolUInt64Dictionary *dict2 = + [GPBBoolUInt64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBBoolUInt64Dictionary *dict = [GPBBoolUInt64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:300U forKey:YES]; + XCTAssertEqual(dict.count, 1U); + + const BOOL kKeys[] = { NO }; + const uint64_t kValues[] = { 301U }; + GPBBoolUInt64Dictionary *dict2 = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + + uint64_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 301U); + [dict2 release]; +} + +- (void)testRemove { + const BOOL kKeys[] = { YES, NO}; + const uint64_t kValues[] = { 300U, 301U }; + GPBBoolUInt64Dictionary *dict = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + uint64_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + // Remove again does nothing. + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const BOOL kKeys[] = { YES, NO }; + const uint64_t kValues[] = { 300U, 301U }; + GPBBoolUInt64Dictionary *dict = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + uint64_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 301U); + + [dict setValue:301U forKey:YES]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 301U); + + [dict setValue:300U forKey:NO]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 300U); + + const BOOL kKeys2[] = { NO, YES }; + const uint64_t kValues2[] = { 301U, 300U }; + GPBBoolUInt64Dictionary *dict2 = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 301U); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND BOOL_TESTS_FOR_POD_VALUE(Int64, int64_t, 400, 401) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> Int64 + +@interface GPBBoolInt64DictionaryTests : XCTestCase +@end + +@implementation GPBBoolInt64DictionaryTests + +- (void)testEmpty { + GPBBoolInt64Dictionary *dict = [[GPBBoolInt64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBBoolInt64Dictionary *dict = [GPBBoolInt64Dictionary dictionaryWithValue:400 forKey:YES]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int64_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int64_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, YES); + XCTAssertEqual(aValue, 400); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const BOOL kKeys[] = { YES, NO }; + const int64_t kValues[] = { 400, 401 }; + GPBBoolInt64Dictionary *dict = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + int64_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 401); + + __block NSUInteger idx = 0; + BOOL *seenKeys = malloc(2 * sizeof(BOOL)); + int64_t *seenValues = malloc(2 * sizeof(int64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 2U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 2; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 2) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 0) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const BOOL kKeys1[] = { YES, NO }; + const BOOL kKeys2[] = { NO, YES }; + const int64_t kValues1[] = { 400, 401 }; + const int64_t kValues2[] = { 401, 400 }; + const int64_t kValues3[] = { 401 }; + GPBBoolInt64Dictionary *dict1 = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBBoolInt64Dictionary *dict1prime = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBBoolInt64Dictionary *dict2 = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBBoolInt64Dictionary *dict3 = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBBoolInt64Dictionary *dict4 = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 Fewer pairs; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const BOOL kKeys[] = { YES, NO }; + const int64_t kValues[] = { 400, 401 }; + GPBBoolInt64Dictionary *dict = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolInt64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBBoolInt64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const BOOL kKeys[] = { YES, NO }; + const int64_t kValues[] = { 400, 401 }; + GPBBoolInt64Dictionary *dict = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolInt64Dictionary *dict2 = + [GPBBoolInt64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBBoolInt64Dictionary *dict = [GPBBoolInt64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:400 forKey:YES]; + XCTAssertEqual(dict.count, 1U); + + const BOOL kKeys[] = { NO }; + const int64_t kValues[] = { 401 }; + GPBBoolInt64Dictionary *dict2 = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + + int64_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 401); + [dict2 release]; +} + +- (void)testRemove { + const BOOL kKeys[] = { YES, NO}; + const int64_t kValues[] = { 400, 401 }; + GPBBoolInt64Dictionary *dict = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + int64_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + // Remove again does nothing. + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const BOOL kKeys[] = { YES, NO }; + const int64_t kValues[] = { 400, 401 }; + GPBBoolInt64Dictionary *dict = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + int64_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 401); + + [dict setValue:401 forKey:YES]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 401); + + [dict setValue:400 forKey:NO]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 400); + + const BOOL kKeys2[] = { NO, YES }; + const int64_t kValues2[] = { 401, 400 }; + GPBBoolInt64Dictionary *dict2 = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 401); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND BOOL_TESTS_FOR_POD_VALUE(Bool, BOOL, NO, YES) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> Bool + +@interface GPBBoolBoolDictionaryTests : XCTestCase +@end + +@implementation GPBBoolBoolDictionaryTests + +- (void)testEmpty { + GPBBoolBoolDictionary *dict = [[GPBBoolBoolDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBBoolBoolDictionary *dict = [GPBBoolBoolDictionary dictionaryWithValue:NO forKey:YES]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + BOOL value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, BOOL aValue, BOOL *stop) { + XCTAssertEqual(aKey, YES); + XCTAssertEqual(aValue, NO); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const BOOL kKeys[] = { YES, NO }; + const BOOL kValues[] = { NO, YES }; + GPBBoolBoolDictionary *dict = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + BOOL value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, YES); + + __block NSUInteger idx = 0; + BOOL *seenKeys = malloc(2 * sizeof(BOOL)); + BOOL *seenValues = malloc(2 * sizeof(BOOL)); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, BOOL aValue, BOOL *stop) { + XCTAssertLessThan(idx, 2U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 2; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 2) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 0) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const BOOL kKeys1[] = { YES, NO }; + const BOOL kKeys2[] = { NO, YES }; + const BOOL kValues1[] = { NO, YES }; + const BOOL kValues2[] = { YES, NO }; + const BOOL kValues3[] = { YES }; + GPBBoolBoolDictionary *dict1 = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBBoolBoolDictionary *dict1prime = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBBoolBoolDictionary *dict2 = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBBoolBoolDictionary *dict3 = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBBoolBoolDictionary *dict4 = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 Fewer pairs; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const BOOL kKeys[] = { YES, NO }; + const BOOL kValues[] = { NO, YES }; + GPBBoolBoolDictionary *dict = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolBoolDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBBoolBoolDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const BOOL kKeys[] = { YES, NO }; + const BOOL kValues[] = { NO, YES }; + GPBBoolBoolDictionary *dict = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolBoolDictionary *dict2 = + [GPBBoolBoolDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBBoolBoolDictionary *dict = [GPBBoolBoolDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:NO forKey:YES]; + XCTAssertEqual(dict.count, 1U); + + const BOOL kKeys[] = { NO }; + const BOOL kValues[] = { YES }; + GPBBoolBoolDictionary *dict2 = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + + BOOL value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, YES); + [dict2 release]; +} + +- (void)testRemove { + const BOOL kKeys[] = { YES, NO}; + const BOOL kValues[] = { NO, YES }; + GPBBoolBoolDictionary *dict = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + BOOL value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + // Remove again does nothing. + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const BOOL kKeys[] = { YES, NO }; + const BOOL kValues[] = { NO, YES }; + GPBBoolBoolDictionary *dict = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + BOOL value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, YES); + + [dict setValue:YES forKey:YES]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, YES); + + [dict setValue:NO forKey:NO]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, NO); + + const BOOL kKeys2[] = { NO, YES }; + const BOOL kValues2[] = { YES, NO }; + GPBBoolBoolDictionary *dict2 = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, YES); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND BOOL_TESTS_FOR_POD_VALUE(Float, float, 500.f, 501.f) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> Float + +@interface GPBBoolFloatDictionaryTests : XCTestCase +@end + +@implementation GPBBoolFloatDictionaryTests + +- (void)testEmpty { + GPBBoolFloatDictionary *dict = [[GPBBoolFloatDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBBoolFloatDictionary *dict = [GPBBoolFloatDictionary dictionaryWithValue:500.f forKey:YES]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + float value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, float aValue, BOOL *stop) { + XCTAssertEqual(aKey, YES); + XCTAssertEqual(aValue, 500.f); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const BOOL kKeys[] = { YES, NO }; + const float kValues[] = { 500.f, 501.f }; + GPBBoolFloatDictionary *dict = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + float value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 501.f); + + __block NSUInteger idx = 0; + BOOL *seenKeys = malloc(2 * sizeof(BOOL)); + float *seenValues = malloc(2 * sizeof(float)); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, float aValue, BOOL *stop) { + XCTAssertLessThan(idx, 2U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 2; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 2) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 0) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const BOOL kKeys1[] = { YES, NO }; + const BOOL kKeys2[] = { NO, YES }; + const float kValues1[] = { 500.f, 501.f }; + const float kValues2[] = { 501.f, 500.f }; + const float kValues3[] = { 501.f }; + GPBBoolFloatDictionary *dict1 = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBBoolFloatDictionary *dict1prime = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBBoolFloatDictionary *dict2 = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBBoolFloatDictionary *dict3 = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBBoolFloatDictionary *dict4 = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 Fewer pairs; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const BOOL kKeys[] = { YES, NO }; + const float kValues[] = { 500.f, 501.f }; + GPBBoolFloatDictionary *dict = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolFloatDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBBoolFloatDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const BOOL kKeys[] = { YES, NO }; + const float kValues[] = { 500.f, 501.f }; + GPBBoolFloatDictionary *dict = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolFloatDictionary *dict2 = + [GPBBoolFloatDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBBoolFloatDictionary *dict = [GPBBoolFloatDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:500.f forKey:YES]; + XCTAssertEqual(dict.count, 1U); + + const BOOL kKeys[] = { NO }; + const float kValues[] = { 501.f }; + GPBBoolFloatDictionary *dict2 = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + + float value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 501.f); + [dict2 release]; +} + +- (void)testRemove { + const BOOL kKeys[] = { YES, NO}; + const float kValues[] = { 500.f, 501.f }; + GPBBoolFloatDictionary *dict = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + float value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + // Remove again does nothing. + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const BOOL kKeys[] = { YES, NO }; + const float kValues[] = { 500.f, 501.f }; + GPBBoolFloatDictionary *dict = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + float value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 501.f); + + [dict setValue:501.f forKey:YES]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 501.f); + + [dict setValue:500.f forKey:NO]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 500.f); + + const BOOL kKeys2[] = { NO, YES }; + const float kValues2[] = { 501.f, 500.f }; + GPBBoolFloatDictionary *dict2 = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 501.f); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND BOOL_TESTS_FOR_POD_VALUE(Double, double, 600., 601.) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> Double + +@interface GPBBoolDoubleDictionaryTests : XCTestCase +@end + +@implementation GPBBoolDoubleDictionaryTests + +- (void)testEmpty { + GPBBoolDoubleDictionary *dict = [[GPBBoolDoubleDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBBoolDoubleDictionary *dict = [GPBBoolDoubleDictionary dictionaryWithValue:600. forKey:YES]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + double value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, double aValue, BOOL *stop) { + XCTAssertEqual(aKey, YES); + XCTAssertEqual(aValue, 600.); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const BOOL kKeys[] = { YES, NO }; + const double kValues[] = { 600., 601. }; + GPBBoolDoubleDictionary *dict = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + double value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 601.); + + __block NSUInteger idx = 0; + BOOL *seenKeys = malloc(2 * sizeof(BOOL)); + double *seenValues = malloc(2 * sizeof(double)); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, double aValue, BOOL *stop) { + XCTAssertLessThan(idx, 2U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 2; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 2) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 0) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const BOOL kKeys1[] = { YES, NO }; + const BOOL kKeys2[] = { NO, YES }; + const double kValues1[] = { 600., 601. }; + const double kValues2[] = { 601., 600. }; + const double kValues3[] = { 601. }; + GPBBoolDoubleDictionary *dict1 = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBBoolDoubleDictionary *dict1prime = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBBoolDoubleDictionary *dict2 = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBBoolDoubleDictionary *dict3 = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBBoolDoubleDictionary *dict4 = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 Fewer pairs; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const BOOL kKeys[] = { YES, NO }; + const double kValues[] = { 600., 601. }; + GPBBoolDoubleDictionary *dict = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolDoubleDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBBoolDoubleDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const BOOL kKeys[] = { YES, NO }; + const double kValues[] = { 600., 601. }; + GPBBoolDoubleDictionary *dict = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolDoubleDictionary *dict2 = + [GPBBoolDoubleDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBBoolDoubleDictionary *dict = [GPBBoolDoubleDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:600. forKey:YES]; + XCTAssertEqual(dict.count, 1U); + + const BOOL kKeys[] = { NO }; + const double kValues[] = { 601. }; + GPBBoolDoubleDictionary *dict2 = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + + double value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 601.); + [dict2 release]; +} + +- (void)testRemove { + const BOOL kKeys[] = { YES, NO}; + const double kValues[] = { 600., 601. }; + GPBBoolDoubleDictionary *dict = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + double value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + // Remove again does nothing. + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const BOOL kKeys[] = { YES, NO }; + const double kValues[] = { 600., 601. }; + GPBBoolDoubleDictionary *dict = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + double value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 601.); + + [dict setValue:601. forKey:YES]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 601.); + + [dict setValue:600. forKey:NO]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 600.); + + const BOOL kKeys2[] = { NO, YES }; + const double kValues2[] = { 601., 600. }; + GPBBoolDoubleDictionary *dict2 = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 601.); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND TESTS_FOR_BOOL_KEY_OBJECT_VALUE(Object, id, @"abc", @"def") +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> Object + +@interface GPBBoolObjectDictionaryTests : XCTestCase +@end + +@implementation GPBBoolObjectDictionaryTests + +- (void)testEmpty { + GPBBoolObjectDictionary *dict = [[GPBBoolObjectDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertNil([dict valueForKey:YES]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, id aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBBoolObjectDictionary *dict = [GPBBoolObjectDictionary dictionaryWithValue:@"abc" forKey:YES]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + XCTAssertEqualObjects([dict valueForKey:YES], @"abc"); + XCTAssertNil([dict valueForKey:NO]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, id aValue, BOOL *stop) { + XCTAssertEqual(aKey, YES); + XCTAssertEqualObjects(aValue, @"abc"); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const BOOL kKeys[] = { YES, NO }; + const id kValues[] = { @"abc", @"def" }; + GPBBoolObjectDictionary *dict = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + XCTAssertEqualObjects([dict valueForKey:YES], @"abc"); + XCTAssertEqualObjects([dict valueForKey:NO], @"def"); + + __block NSUInteger idx = 0; + BOOL *seenKeys = malloc(2 * sizeof(BOOL)); + id *seenValues = malloc(2 * sizeof(id)); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, id aValue, BOOL *stop) { + XCTAssertLessThan(idx, 2U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 2; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 2) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqualObjects(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, id aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 0) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const BOOL kKeys1[] = { YES, NO }; + const BOOL kKeys2[] = { NO, YES }; + const id kValues1[] = { @"abc", @"def" }; + const id kValues2[] = { @"def", @"abc" }; + const id kValues3[] = { @"def" }; + GPBBoolObjectDictionary *dict1 = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBBoolObjectDictionary *dict1prime = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBBoolObjectDictionary *dict2 = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBBoolObjectDictionary *dict3 = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBBoolObjectDictionary *dict4 = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 Fewer pairs; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const BOOL kKeys[] = { YES, NO }; + const id kValues[] = { @"abc", @"def" }; + GPBBoolObjectDictionary *dict = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolObjectDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBBoolObjectDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const BOOL kKeys[] = { YES, NO }; + const id kValues[] = { @"abc", @"def" }; + GPBBoolObjectDictionary *dict = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolObjectDictionary *dict2 = + [GPBBoolObjectDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBBoolObjectDictionary *dict = [GPBBoolObjectDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:@"abc" forKey:YES]; + XCTAssertEqual(dict.count, 1U); + + const BOOL kKeys[] = { NO }; + const id kValues[] = { @"def" }; + GPBBoolObjectDictionary *dict2 = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + + XCTAssertEqualObjects([dict valueForKey:YES], @"abc"); + XCTAssertEqualObjects([dict valueForKey:NO], @"def"); + [dict2 release]; +} + +- (void)testRemove { + const BOOL kKeys[] = { YES, NO}; + const id kValues[] = { @"abc", @"def" }; + GPBBoolObjectDictionary *dict = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + XCTAssertEqualObjects([dict valueForKey:YES], @"abc"); + XCTAssertNil([dict valueForKey:NO]); + + // Remove again does nothing. + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + XCTAssertEqualObjects([dict valueForKey:YES], @"abc"); + XCTAssertNil([dict valueForKey:NO]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertNil([dict valueForKey:YES]); + XCTAssertNil([dict valueForKey:NO]); + [dict release]; +} + +- (void)testInplaceMutation { + const BOOL kKeys[] = { YES, NO }; + const id kValues[] = { @"abc", @"def" }; + GPBBoolObjectDictionary *dict = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + XCTAssertEqualObjects([dict valueForKey:YES], @"abc"); + XCTAssertEqualObjects([dict valueForKey:NO], @"def"); + + [dict setValue:@"def" forKey:YES]; + XCTAssertEqual(dict.count, 2U); + XCTAssertEqualObjects([dict valueForKey:YES], @"def"); + XCTAssertEqualObjects([dict valueForKey:NO], @"def"); + + [dict setValue:@"abc" forKey:NO]; + XCTAssertEqual(dict.count, 2U); + XCTAssertEqualObjects([dict valueForKey:YES], @"def"); + XCTAssertEqualObjects([dict valueForKey:NO], @"abc"); + + const BOOL kKeys2[] = { NO, YES }; + const id kValues2[] = { @"def", @"abc" }; + GPBBoolObjectDictionary *dict2 = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + XCTAssertEqualObjects([dict valueForKey:YES], @"abc"); + XCTAssertEqualObjects([dict valueForKey:NO], @"def"); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND-END (8 expansions) + + diff --git a/objectivec/Tests/GPBDictionaryTests+Int32.m b/objectivec/Tests/GPBDictionaryTests+Int32.m new file mode 100644 index 00000000..5e25799c --- /dev/null +++ b/objectivec/Tests/GPBDictionaryTests+Int32.m @@ -0,0 +1,3650 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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. + +#import <Foundation/Foundation.h> +#import <XCTest/XCTest.h> + +#import "GPBDictionary.h" + +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h" + +// Pull in the macros (using an external file because expanding all tests +// in a single file makes a file that is failing to work with within Xcode. +//%PDDM-IMPORT-DEFINES GPBDictionaryTests.pddm + +//%PDDM-EXPAND TEST_FOR_POD_KEY(Int32, int32_t, 11, 12, 13, 14) +// This block of code is generated, do not edit it directly. + +#ifndef GPBARRAYSIZE +#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0])))) +#endif // GPBARRAYSIZE + +// To let the testing macros work, add some extra methods to simplify things. +@interface GPBInt32EnumDictionary (TestingTweak) ++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(int32_t)key; +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count; +@end + +static BOOL TestingEnum_IsValidValue(int32_t value) { + switch (value) { + case 700: + case 701: + case 702: + case 703: + return YES; + default: + return NO; + } +} + +@implementation GPBInt32EnumDictionary (TestingTweak) ++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(int32_t)key { + // Cast is needed to compiler knows what class we are invoking initWithValues: on to get the + // type correct. + return [[(GPBInt32EnumDictionary*)[self alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:&value + forKeys:&key + count:1] autorelease]; +} +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count { + return [self initWithValidationFunction:TestingEnum_IsValidValue + rawValues:values + forKeys:keys + count:count]; +} +@end + + +#pragma mark - Int32 -> UInt32 + +@interface GPBInt32UInt32DictionaryTests : XCTestCase +@end + +@implementation GPBInt32UInt32DictionaryTests + +- (void)testEmpty { + GPBInt32UInt32Dictionary *dict = [[GPBInt32UInt32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt32UInt32Dictionary *dict = [GPBInt32UInt32Dictionary dictionaryWithValue:100U forKey:11]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 11); + XCTAssertEqual(aValue, 100U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int32_t kKeys[] = { 11, 12, 13 }; + const uint32_t kValues[] = { 100U, 101U, 102U }; + GPBInt32UInt32Dictionary *dict = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + uint32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + __block NSUInteger idx = 0; + int32_t *seenKeys = malloc(3 * sizeof(int32_t)); + uint32_t *seenValues = malloc(3 * sizeof(uint32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int32_t kKeys1[] = { 11, 12, 13, 14 }; + const int32_t kKeys2[] = { 12, 11, 14 }; + const uint32_t kValues1[] = { 100U, 101U, 102U }; + const uint32_t kValues2[] = { 100U, 103U, 102U }; + const uint32_t kValues3[] = { 100U, 101U, 102U, 103U }; + GPBInt32UInt32Dictionary *dict1 = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt32UInt32Dictionary *dict1prime = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt32UInt32Dictionary *dict2 = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt32UInt32Dictionary *dict3 = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt32UInt32Dictionary *dict4 = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBInt32UInt32Dictionary *dict = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32UInt32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt32UInt32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBInt32UInt32Dictionary *dict = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32UInt32Dictionary *dict2 = + [GPBInt32UInt32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt32UInt32Dictionary *dict = [GPBInt32UInt32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:100U forKey:11]; + XCTAssertEqual(dict.count, 1U); + + const int32_t kKeys[] = { 12, 13, 14 }; + const uint32_t kValues[] = { 101U, 102U, 103U }; + GPBInt32UInt32Dictionary *dict2 = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + uint32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 103U); + [dict2 release]; +} + +- (void)testRemove { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBInt32UInt32Dictionary *dict = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + uint32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 103U); + + // Remove again does nothing. + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 103U); + + [dict removeValueForKey:14]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertFalse([dict valueForKey:13 value:NULL]); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBInt32UInt32Dictionary *dict = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + uint32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 103U); + + [dict setValue:103U forKey:11]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 103U); + + [dict setValue:101U forKey:14]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 101U); + + const int32_t kKeys2[] = { 12, 13 }; + const uint32_t kValues2[] = { 102U, 100U }; + GPBInt32UInt32Dictionary *dict2 = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 101U); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int32 -> Int32 + +@interface GPBInt32Int32DictionaryTests : XCTestCase +@end + +@implementation GPBInt32Int32DictionaryTests + +- (void)testEmpty { + GPBInt32Int32Dictionary *dict = [[GPBInt32Int32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt32Int32Dictionary *dict = [GPBInt32Int32Dictionary dictionaryWithValue:200 forKey:11]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 11); + XCTAssertEqual(aValue, 200); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int32_t kKeys[] = { 11, 12, 13 }; + const int32_t kValues[] = { 200, 201, 202 }; + GPBInt32Int32Dictionary *dict = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 202); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + __block NSUInteger idx = 0; + int32_t *seenKeys = malloc(3 * sizeof(int32_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int32_t kKeys1[] = { 11, 12, 13, 14 }; + const int32_t kKeys2[] = { 12, 11, 14 }; + const int32_t kValues1[] = { 200, 201, 202 }; + const int32_t kValues2[] = { 200, 203, 202 }; + const int32_t kValues3[] = { 200, 201, 202, 203 }; + GPBInt32Int32Dictionary *dict1 = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt32Int32Dictionary *dict1prime = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt32Int32Dictionary *dict2 = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt32Int32Dictionary *dict3 = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt32Int32Dictionary *dict4 = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBInt32Int32Dictionary *dict = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32Int32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt32Int32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBInt32Int32Dictionary *dict = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32Int32Dictionary *dict2 = + [GPBInt32Int32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt32Int32Dictionary *dict = [GPBInt32Int32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:200 forKey:11]; + XCTAssertEqual(dict.count, 1U); + + const int32_t kKeys[] = { 12, 13, 14 }; + const int32_t kValues[] = { 201, 202, 203 }; + GPBInt32Int32Dictionary *dict2 = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 203); + [dict2 release]; +} + +- (void)testRemove { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBInt32Int32Dictionary *dict = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 203); + + // Remove again does nothing. + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 203); + + [dict removeValueForKey:14]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 202); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertFalse([dict valueForKey:13 value:NULL]); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBInt32Int32Dictionary *dict = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 203); + + [dict setValue:203 forKey:11]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 203); + + [dict setValue:201 forKey:14]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 201); + + const int32_t kKeys2[] = { 12, 13 }; + const int32_t kValues2[] = { 202, 200 }; + GPBInt32Int32Dictionary *dict2 = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 201); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int32 -> UInt64 + +@interface GPBInt32UInt64DictionaryTests : XCTestCase +@end + +@implementation GPBInt32UInt64DictionaryTests + +- (void)testEmpty { + GPBInt32UInt64Dictionary *dict = [[GPBInt32UInt64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt32UInt64Dictionary *dict = [GPBInt32UInt64Dictionary dictionaryWithValue:300U forKey:11]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint64_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint64_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 11); + XCTAssertEqual(aValue, 300U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int32_t kKeys[] = { 11, 12, 13 }; + const uint64_t kValues[] = { 300U, 301U, 302U }; + GPBInt32UInt64Dictionary *dict = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + uint64_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + __block NSUInteger idx = 0; + int32_t *seenKeys = malloc(3 * sizeof(int32_t)); + uint64_t *seenValues = malloc(3 * sizeof(uint64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int32_t kKeys1[] = { 11, 12, 13, 14 }; + const int32_t kKeys2[] = { 12, 11, 14 }; + const uint64_t kValues1[] = { 300U, 301U, 302U }; + const uint64_t kValues2[] = { 300U, 303U, 302U }; + const uint64_t kValues3[] = { 300U, 301U, 302U, 303U }; + GPBInt32UInt64Dictionary *dict1 = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt32UInt64Dictionary *dict1prime = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt32UInt64Dictionary *dict2 = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt32UInt64Dictionary *dict3 = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt32UInt64Dictionary *dict4 = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBInt32UInt64Dictionary *dict = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32UInt64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt32UInt64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBInt32UInt64Dictionary *dict = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32UInt64Dictionary *dict2 = + [GPBInt32UInt64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt32UInt64Dictionary *dict = [GPBInt32UInt64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:300U forKey:11]; + XCTAssertEqual(dict.count, 1U); + + const int32_t kKeys[] = { 12, 13, 14 }; + const uint64_t kValues[] = { 301U, 302U, 303U }; + GPBInt32UInt64Dictionary *dict2 = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + uint64_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 303U); + [dict2 release]; +} + +- (void)testRemove { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBInt32UInt64Dictionary *dict = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + uint64_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 303U); + + // Remove again does nothing. + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 303U); + + [dict removeValueForKey:14]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertFalse([dict valueForKey:13 value:NULL]); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBInt32UInt64Dictionary *dict = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + uint64_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 303U); + + [dict setValue:303U forKey:11]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 303U); + + [dict setValue:301U forKey:14]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 301U); + + const int32_t kKeys2[] = { 12, 13 }; + const uint64_t kValues2[] = { 302U, 300U }; + GPBInt32UInt64Dictionary *dict2 = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 301U); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int32 -> Int64 + +@interface GPBInt32Int64DictionaryTests : XCTestCase +@end + +@implementation GPBInt32Int64DictionaryTests + +- (void)testEmpty { + GPBInt32Int64Dictionary *dict = [[GPBInt32Int64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt32Int64Dictionary *dict = [GPBInt32Int64Dictionary dictionaryWithValue:400 forKey:11]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int64_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int64_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 11); + XCTAssertEqual(aValue, 400); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int32_t kKeys[] = { 11, 12, 13 }; + const int64_t kValues[] = { 400, 401, 402 }; + GPBInt32Int64Dictionary *dict = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int64_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 402); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + __block NSUInteger idx = 0; + int32_t *seenKeys = malloc(3 * sizeof(int32_t)); + int64_t *seenValues = malloc(3 * sizeof(int64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int32_t kKeys1[] = { 11, 12, 13, 14 }; + const int32_t kKeys2[] = { 12, 11, 14 }; + const int64_t kValues1[] = { 400, 401, 402 }; + const int64_t kValues2[] = { 400, 403, 402 }; + const int64_t kValues3[] = { 400, 401, 402, 403 }; + GPBInt32Int64Dictionary *dict1 = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt32Int64Dictionary *dict1prime = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt32Int64Dictionary *dict2 = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt32Int64Dictionary *dict3 = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt32Int64Dictionary *dict4 = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBInt32Int64Dictionary *dict = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32Int64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt32Int64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBInt32Int64Dictionary *dict = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32Int64Dictionary *dict2 = + [GPBInt32Int64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt32Int64Dictionary *dict = [GPBInt32Int64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:400 forKey:11]; + XCTAssertEqual(dict.count, 1U); + + const int32_t kKeys[] = { 12, 13, 14 }; + const int64_t kValues[] = { 401, 402, 403 }; + GPBInt32Int64Dictionary *dict2 = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int64_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 403); + [dict2 release]; +} + +- (void)testRemove { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBInt32Int64Dictionary *dict = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + int64_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 403); + + // Remove again does nothing. + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 403); + + [dict removeValueForKey:14]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 402); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertFalse([dict valueForKey:13 value:NULL]); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBInt32Int64Dictionary *dict = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int64_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 403); + + [dict setValue:403 forKey:11]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 403); + + [dict setValue:401 forKey:14]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 401); + + const int32_t kKeys2[] = { 12, 13 }; + const int64_t kValues2[] = { 402, 400 }; + GPBInt32Int64Dictionary *dict2 = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 401); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int32 -> Bool + +@interface GPBInt32BoolDictionaryTests : XCTestCase +@end + +@implementation GPBInt32BoolDictionaryTests + +- (void)testEmpty { + GPBInt32BoolDictionary *dict = [[GPBInt32BoolDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt32BoolDictionary *dict = [GPBInt32BoolDictionary dictionaryWithValue:YES forKey:11]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + BOOL value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, BOOL aValue, BOOL *stop) { + XCTAssertEqual(aKey, 11); + XCTAssertEqual(aValue, YES); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int32_t kKeys[] = { 11, 12, 13 }; + const BOOL kValues[] = { YES, YES, NO }; + GPBInt32BoolDictionary *dict = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + BOOL value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + __block NSUInteger idx = 0; + int32_t *seenKeys = malloc(3 * sizeof(int32_t)); + BOOL *seenValues = malloc(3 * sizeof(BOOL)); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, BOOL aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int32_t kKeys1[] = { 11, 12, 13, 14 }; + const int32_t kKeys2[] = { 12, 11, 14 }; + const BOOL kValues1[] = { YES, YES, NO }; + const BOOL kValues2[] = { YES, NO, NO }; + const BOOL kValues3[] = { YES, YES, NO, NO }; + GPBInt32BoolDictionary *dict1 = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt32BoolDictionary *dict1prime = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt32BoolDictionary *dict2 = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt32BoolDictionary *dict3 = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt32BoolDictionary *dict4 = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBInt32BoolDictionary *dict = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32BoolDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt32BoolDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBInt32BoolDictionary *dict = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32BoolDictionary *dict2 = + [GPBInt32BoolDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt32BoolDictionary *dict = [GPBInt32BoolDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:YES forKey:11]; + XCTAssertEqual(dict.count, 1U); + + const int32_t kKeys[] = { 12, 13, 14 }; + const BOOL kValues[] = { YES, NO, NO }; + GPBInt32BoolDictionary *dict2 = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + BOOL value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, NO); + [dict2 release]; +} + +- (void)testRemove { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBInt32BoolDictionary *dict = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + BOOL value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, NO); + + // Remove again does nothing. + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, NO); + + [dict removeValueForKey:14]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertFalse([dict valueForKey:13 value:NULL]); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBInt32BoolDictionary *dict = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + BOOL value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, NO); + + [dict setValue:NO forKey:11]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, NO); + + [dict setValue:YES forKey:14]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, YES); + + const int32_t kKeys2[] = { 12, 13 }; + const BOOL kValues2[] = { NO, YES }; + GPBInt32BoolDictionary *dict2 = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, YES); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int32 -> Float + +@interface GPBInt32FloatDictionaryTests : XCTestCase +@end + +@implementation GPBInt32FloatDictionaryTests + +- (void)testEmpty { + GPBInt32FloatDictionary *dict = [[GPBInt32FloatDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt32FloatDictionary *dict = [GPBInt32FloatDictionary dictionaryWithValue:500.f forKey:11]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + float value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, float aValue, BOOL *stop) { + XCTAssertEqual(aKey, 11); + XCTAssertEqual(aValue, 500.f); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int32_t kKeys[] = { 11, 12, 13 }; + const float kValues[] = { 500.f, 501.f, 502.f }; + GPBInt32FloatDictionary *dict = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + float value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + __block NSUInteger idx = 0; + int32_t *seenKeys = malloc(3 * sizeof(int32_t)); + float *seenValues = malloc(3 * sizeof(float)); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, float aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int32_t kKeys1[] = { 11, 12, 13, 14 }; + const int32_t kKeys2[] = { 12, 11, 14 }; + const float kValues1[] = { 500.f, 501.f, 502.f }; + const float kValues2[] = { 500.f, 503.f, 502.f }; + const float kValues3[] = { 500.f, 501.f, 502.f, 503.f }; + GPBInt32FloatDictionary *dict1 = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt32FloatDictionary *dict1prime = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt32FloatDictionary *dict2 = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt32FloatDictionary *dict3 = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt32FloatDictionary *dict4 = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBInt32FloatDictionary *dict = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32FloatDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt32FloatDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBInt32FloatDictionary *dict = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32FloatDictionary *dict2 = + [GPBInt32FloatDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt32FloatDictionary *dict = [GPBInt32FloatDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:500.f forKey:11]; + XCTAssertEqual(dict.count, 1U); + + const int32_t kKeys[] = { 12, 13, 14 }; + const float kValues[] = { 501.f, 502.f, 503.f }; + GPBInt32FloatDictionary *dict2 = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + float value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 503.f); + [dict2 release]; +} + +- (void)testRemove { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBInt32FloatDictionary *dict = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + float value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 503.f); + + // Remove again does nothing. + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 503.f); + + [dict removeValueForKey:14]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertFalse([dict valueForKey:13 value:NULL]); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBInt32FloatDictionary *dict = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + float value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 503.f); + + [dict setValue:503.f forKey:11]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 503.f); + + [dict setValue:501.f forKey:14]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 501.f); + + const int32_t kKeys2[] = { 12, 13 }; + const float kValues2[] = { 502.f, 500.f }; + GPBInt32FloatDictionary *dict2 = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 501.f); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int32 -> Double + +@interface GPBInt32DoubleDictionaryTests : XCTestCase +@end + +@implementation GPBInt32DoubleDictionaryTests + +- (void)testEmpty { + GPBInt32DoubleDictionary *dict = [[GPBInt32DoubleDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt32DoubleDictionary *dict = [GPBInt32DoubleDictionary dictionaryWithValue:600. forKey:11]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + double value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, double aValue, BOOL *stop) { + XCTAssertEqual(aKey, 11); + XCTAssertEqual(aValue, 600.); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int32_t kKeys[] = { 11, 12, 13 }; + const double kValues[] = { 600., 601., 602. }; + GPBInt32DoubleDictionary *dict = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + double value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + __block NSUInteger idx = 0; + int32_t *seenKeys = malloc(3 * sizeof(int32_t)); + double *seenValues = malloc(3 * sizeof(double)); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, double aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int32_t kKeys1[] = { 11, 12, 13, 14 }; + const int32_t kKeys2[] = { 12, 11, 14 }; + const double kValues1[] = { 600., 601., 602. }; + const double kValues2[] = { 600., 603., 602. }; + const double kValues3[] = { 600., 601., 602., 603. }; + GPBInt32DoubleDictionary *dict1 = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt32DoubleDictionary *dict1prime = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt32DoubleDictionary *dict2 = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt32DoubleDictionary *dict3 = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt32DoubleDictionary *dict4 = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBInt32DoubleDictionary *dict = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32DoubleDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt32DoubleDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBInt32DoubleDictionary *dict = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32DoubleDictionary *dict2 = + [GPBInt32DoubleDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt32DoubleDictionary *dict = [GPBInt32DoubleDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:600. forKey:11]; + XCTAssertEqual(dict.count, 1U); + + const int32_t kKeys[] = { 12, 13, 14 }; + const double kValues[] = { 601., 602., 603. }; + GPBInt32DoubleDictionary *dict2 = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + double value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 603.); + [dict2 release]; +} + +- (void)testRemove { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBInt32DoubleDictionary *dict = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + double value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 603.); + + // Remove again does nothing. + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 603.); + + [dict removeValueForKey:14]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertFalse([dict valueForKey:13 value:NULL]); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBInt32DoubleDictionary *dict = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + double value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 603.); + + [dict setValue:603. forKey:11]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 603.); + + [dict setValue:601. forKey:14]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 601.); + + const int32_t kKeys2[] = { 12, 13 }; + const double kValues2[] = { 602., 600. }; + GPBInt32DoubleDictionary *dict2 = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 601.); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int32 -> Enum + +@interface GPBInt32EnumDictionaryTests : XCTestCase +@end + +@implementation GPBInt32EnumDictionaryTests + +- (void)testEmpty { + GPBInt32EnumDictionary *dict = [[GPBInt32EnumDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt32EnumDictionary *dict = [GPBInt32EnumDictionary dictionaryWithValue:700 forKey:11]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 11); + XCTAssertEqual(aValue, 700); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int32_t kKeys[] = { 11, 12, 13 }; + const int32_t kValues[] = { 700, 701, 702 }; + GPBInt32EnumDictionary *dict = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + __block NSUInteger idx = 0; + int32_t *seenKeys = malloc(3 * sizeof(int32_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int32_t kKeys1[] = { 11, 12, 13, 14 }; + const int32_t kKeys2[] = { 12, 11, 14 }; + const int32_t kValues1[] = { 700, 701, 702 }; + const int32_t kValues2[] = { 700, 703, 702 }; + const int32_t kValues3[] = { 700, 701, 702, 703 }; + GPBInt32EnumDictionary *dict1 = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt32EnumDictionary *dict1prime = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt32EnumDictionary *dict2 = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt32EnumDictionary *dict3 = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt32EnumDictionary *dict4 = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBInt32EnumDictionary *dict = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt32EnumDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBInt32EnumDictionary *dict = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32EnumDictionary *dict2 = + [GPBInt32EnumDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt32EnumDictionary *dict = [GPBInt32EnumDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:700 forKey:11]; + XCTAssertEqual(dict.count, 1U); + + const int32_t kKeys[] = { 12, 13, 14 }; + const int32_t kValues[] = { 701, 702, 703 }; + GPBInt32EnumDictionary *dict2 = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 703); + [dict2 release]; +} + +- (void)testRemove { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBInt32EnumDictionary *dict = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 703); + + // Remove again does nothing. + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 703); + + [dict removeValueForKey:14]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertFalse([dict valueForKey:13 value:NULL]); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBInt32EnumDictionary *dict = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 703); + + [dict setValue:703 forKey:11]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 703); + + [dict setValue:701 forKey:14]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 701); + + const int32_t kKeys2[] = { 12, 13 }; + const int32_t kValues2[] = { 702, 700 }; + GPBInt32EnumDictionary *dict2 = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 701); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int32 -> Enum (Unknown Enums) + +@interface GPBInt32EnumDictionaryUnknownEnumTests : XCTestCase +@end + +@implementation GPBInt32EnumDictionaryUnknownEnumTests + +- (void)testRawBasics { + const int32_t kKeys[] = { 11, 12, 13 }; + const int32_t kValues[] = { 700, 801, 702 }; + GPBInt32EnumDictionary *dict = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue(dict.validationFunc == TestingEnum_IsValidValue); // Pointer comparison + int32_t value; + XCTAssertTrue([dict valueForKey:11 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:11 rawValue:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:12 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:12 rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:13 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:13 rawValue:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:14 rawValue:NULL]); + + __block NSUInteger idx = 0; + int32_t *seenKeys = malloc(3 * sizeof(int32_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + if (i == 1) { + XCTAssertEqual(kGPBUnrecognizedEnumeratorValue, seenValues[j], @"i = %d, j = %d", i, j); + } else { + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + idx = 0; + [dict enumerateKeysAndRawValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndRawValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEqualityWithUnknowns { + const int32_t kKeys1[] = { 11, 12, 13, 14 }; + const int32_t kKeys2[] = { 12, 11, 14 }; + const int32_t kValues1[] = { 700, 801, 702 }; // Unknown + const int32_t kValues2[] = { 700, 803, 702 }; // Unknown + const int32_t kValues3[] = { 700, 801, 702, 803 }; // Unknowns + GPBInt32EnumDictionary *dict1 = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt32EnumDictionary *dict1prime = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt32EnumDictionary *dict2 = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt32EnumDictionary *dict3 = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt32EnumDictionary *dict4 = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopyWithUnknowns { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknown + GPBInt32EnumDictionary *dict = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + XCTAssertEqualObjects(dict, dict2); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBInt32EnumDictionary *dict = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32EnumDictionary *dict2 = + [GPBInt32EnumDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + [dict release]; +} + +- (void)testUnknownAdds { + GPBInt32EnumDictionary *dict = + [GPBInt32EnumDictionary dictionaryWithValidationFunction:TestingEnum_IsValidValue]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + XCTAssertThrowsSpecificNamed([dict setValue:801 forKey:12], // Unknown + NSException, NSInvalidArgumentException); + XCTAssertEqual(dict.count, 0U); + [dict setRawValue:801 forKey:12]; // Unknown + XCTAssertEqual(dict.count, 1U); + + const int32_t kKeys[] = { 11, 13, 14 }; + const int32_t kValues[] = { 700, 702, 803 }; // Unknown + GPBInt32EnumDictionary *dict2 = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:12 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:12 rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:14 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:14 rawValue:&value]); + XCTAssertEqual(value, 803); + [dict2 release]; +} + +- (void)testUnknownRemove { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBInt32EnumDictionary *dict = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:14 rawValue:&value]); + XCTAssertEqual(value, 803); + + // Remove again does nothing. + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:14 rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict removeValueForKey:14]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertFalse([dict valueForKey:13 value:NULL]); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + [dict release]; +} + +- (void)testInplaceMutationUnknowns { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBInt32EnumDictionary *dict = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:12 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:12 rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:14 rawValue:&value]); + XCTAssertEqual(value, 803); + + XCTAssertThrowsSpecificNamed([dict setValue:803 forKey:11], // Unknown + NSException, NSInvalidArgumentException); + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:12 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:12 rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:14 rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict setRawValue:803 forKey:11]; // Unknown + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:11 rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:12 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:12 rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:14 rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict setRawValue:700 forKey:14]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:11 rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:12 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:12 rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 700); + + const int32_t kKeys2[] = { 12, 13 }; + const int32_t kValues2[] = { 702, 801 }; // Unknown + GPBInt32EnumDictionary *dict2 = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:11 rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:13 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:13 rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 700); + + [dict2 release]; + [dict release]; +} + +- (void)testCopyUnknowns { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 700, 801, 702, 803 }; + GPBInt32EnumDictionary *dict = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + XCTAssertTrue([dict2 isKindOfClass:[GPBInt32EnumDictionary class]]); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int32 -> Object + +@interface GPBInt32ObjectDictionaryTests : XCTestCase +@end + +@implementation GPBInt32ObjectDictionaryTests + +- (void)testEmpty { + GPBInt32ObjectDictionary *dict = [[GPBInt32ObjectDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertNil([dict valueForKey:11]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, id aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt32ObjectDictionary *dict = [GPBInt32ObjectDictionary dictionaryWithValue:@"abc" forKey:11]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + XCTAssertEqualObjects([dict valueForKey:11], @"abc"); + XCTAssertNil([dict valueForKey:12]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, id aValue, BOOL *stop) { + XCTAssertEqual(aKey, 11); + XCTAssertEqualObjects(aValue, @"abc"); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int32_t kKeys[] = { 11, 12, 13 }; + const id kValues[] = { @"abc", @"def", @"ghi" }; + GPBInt32ObjectDictionary *dict = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:11], @"abc"); + XCTAssertEqualObjects([dict valueForKey:12], @"def"); + XCTAssertEqualObjects([dict valueForKey:13], @"ghi"); + XCTAssertNil([dict valueForKey:14]); + + __block NSUInteger idx = 0; + int32_t *seenKeys = malloc(3 * sizeof(int32_t)); + id *seenValues = malloc(3 * sizeof(id)); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, id aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqualObjects(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, id aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int32_t kKeys1[] = { 11, 12, 13, 14 }; + const int32_t kKeys2[] = { 12, 11, 14 }; + const id kValues1[] = { @"abc", @"def", @"ghi" }; + const id kValues2[] = { @"abc", @"jkl", @"ghi" }; + const id kValues3[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBInt32ObjectDictionary *dict1 = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt32ObjectDictionary *dict1prime = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt32ObjectDictionary *dict2 = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt32ObjectDictionary *dict3 = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt32ObjectDictionary *dict4 = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBInt32ObjectDictionary *dict = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32ObjectDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt32ObjectDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBInt32ObjectDictionary *dict = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32ObjectDictionary *dict2 = + [GPBInt32ObjectDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt32ObjectDictionary *dict = [GPBInt32ObjectDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:@"abc" forKey:11]; + XCTAssertEqual(dict.count, 1U); + + const int32_t kKeys[] = { 12, 13, 14 }; + const id kValues[] = { @"def", @"ghi", @"jkl" }; + GPBInt32ObjectDictionary *dict2 = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + XCTAssertEqualObjects([dict valueForKey:11], @"abc"); + XCTAssertEqualObjects([dict valueForKey:12], @"def"); + XCTAssertEqualObjects([dict valueForKey:13], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:14], @"jkl"); + [dict2 release]; +} + +- (void)testRemove { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBInt32ObjectDictionary *dict = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:11], @"abc"); + XCTAssertNil([dict valueForKey:12]); + XCTAssertEqualObjects([dict valueForKey:13], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:14], @"jkl"); + + // Remove again does nothing. + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:11], @"abc"); + XCTAssertNil([dict valueForKey:12]); + XCTAssertEqualObjects([dict valueForKey:13], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:14], @"jkl"); + + [dict removeValueForKey:14]; + XCTAssertEqual(dict.count, 2U); + XCTAssertEqualObjects([dict valueForKey:11], @"abc"); + XCTAssertNil([dict valueForKey:12]); + XCTAssertEqualObjects([dict valueForKey:13], @"ghi"); + XCTAssertNil([dict valueForKey:14]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertNil([dict valueForKey:11]); + XCTAssertNil([dict valueForKey:12]); + XCTAssertNil([dict valueForKey:13]); + XCTAssertNil([dict valueForKey:14]); + [dict release]; +} + +- (void)testInplaceMutation { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBInt32ObjectDictionary *dict = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:11], @"abc"); + XCTAssertEqualObjects([dict valueForKey:12], @"def"); + XCTAssertEqualObjects([dict valueForKey:13], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:14], @"jkl"); + + [dict setValue:@"jkl" forKey:11]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:11], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:12], @"def"); + XCTAssertEqualObjects([dict valueForKey:13], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:14], @"jkl"); + + [dict setValue:@"def" forKey:14]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:11], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:12], @"def"); + XCTAssertEqualObjects([dict valueForKey:13], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:14], @"def"); + + const int32_t kKeys2[] = { 12, 13 }; + const id kValues2[] = { @"ghi", @"abc" }; + GPBInt32ObjectDictionary *dict2 = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:11], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:12], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:13], @"abc"); + XCTAssertEqualObjects([dict valueForKey:14], @"def"); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND-END TEST_FOR_POD_KEY(Int32, int32_t, 11, 12, 13, 14) + diff --git a/objectivec/Tests/GPBDictionaryTests+Int64.m b/objectivec/Tests/GPBDictionaryTests+Int64.m new file mode 100644 index 00000000..6e794d38 --- /dev/null +++ b/objectivec/Tests/GPBDictionaryTests+Int64.m @@ -0,0 +1,3650 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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. + +#import <Foundation/Foundation.h> +#import <XCTest/XCTest.h> + +#import "GPBDictionary.h" + +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h" + +// Pull in the macros (using an external file because expanding all tests +// in a single file makes a file that is failing to work with within Xcode. +//%PDDM-IMPORT-DEFINES GPBDictionaryTests.pddm + +//%PDDM-EXPAND TEST_FOR_POD_KEY(Int64, int64_t, 21LL, 22LL, 23LL, 24LL) +// This block of code is generated, do not edit it directly. + +#ifndef GPBARRAYSIZE +#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0])))) +#endif // GPBARRAYSIZE + +// To let the testing macros work, add some extra methods to simplify things. +@interface GPBInt64EnumDictionary (TestingTweak) ++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(int64_t)key; +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count; +@end + +static BOOL TestingEnum_IsValidValue(int32_t value) { + switch (value) { + case 700: + case 701: + case 702: + case 703: + return YES; + default: + return NO; + } +} + +@implementation GPBInt64EnumDictionary (TestingTweak) ++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(int64_t)key { + // Cast is needed to compiler knows what class we are invoking initWithValues: on to get the + // type correct. + return [[(GPBInt64EnumDictionary*)[self alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:&value + forKeys:&key + count:1] autorelease]; +} +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count { + return [self initWithValidationFunction:TestingEnum_IsValidValue + rawValues:values + forKeys:keys + count:count]; +} +@end + + +#pragma mark - Int64 -> UInt32 + +@interface GPBInt64UInt32DictionaryTests : XCTestCase +@end + +@implementation GPBInt64UInt32DictionaryTests + +- (void)testEmpty { + GPBInt64UInt32Dictionary *dict = [[GPBInt64UInt32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt64UInt32Dictionary *dict = [GPBInt64UInt32Dictionary dictionaryWithValue:100U forKey:21LL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 21LL); + XCTAssertEqual(aValue, 100U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int64_t kKeys[] = { 21LL, 22LL, 23LL }; + const uint32_t kValues[] = { 100U, 101U, 102U }; + GPBInt64UInt32Dictionary *dict = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + uint32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + __block NSUInteger idx = 0; + int64_t *seenKeys = malloc(3 * sizeof(int64_t)); + uint32_t *seenValues = malloc(3 * sizeof(uint32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kKeys2[] = { 22LL, 21LL, 24LL }; + const uint32_t kValues1[] = { 100U, 101U, 102U }; + const uint32_t kValues2[] = { 100U, 103U, 102U }; + const uint32_t kValues3[] = { 100U, 101U, 102U, 103U }; + GPBInt64UInt32Dictionary *dict1 = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt64UInt32Dictionary *dict1prime = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt64UInt32Dictionary *dict2 = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt64UInt32Dictionary *dict3 = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt64UInt32Dictionary *dict4 = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBInt64UInt32Dictionary *dict = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64UInt32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt64UInt32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBInt64UInt32Dictionary *dict = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64UInt32Dictionary *dict2 = + [GPBInt64UInt32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt64UInt32Dictionary *dict = [GPBInt64UInt32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:100U forKey:21LL]; + XCTAssertEqual(dict.count, 1U); + + const int64_t kKeys[] = { 22LL, 23LL, 24LL }; + const uint32_t kValues[] = { 101U, 102U, 103U }; + GPBInt64UInt32Dictionary *dict2 = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + uint32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 103U); + [dict2 release]; +} + +- (void)testRemove { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBInt64UInt32Dictionary *dict = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + uint32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 103U); + + // Remove again does nothing. + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 103U); + + [dict removeValueForKey:24LL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertFalse([dict valueForKey:23LL value:NULL]); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBInt64UInt32Dictionary *dict = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + uint32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 103U); + + [dict setValue:103U forKey:21LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 103U); + + [dict setValue:101U forKey:24LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 101U); + + const int64_t kKeys2[] = { 22LL, 23LL }; + const uint32_t kValues2[] = { 102U, 100U }; + GPBInt64UInt32Dictionary *dict2 = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 101U); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int64 -> Int32 + +@interface GPBInt64Int32DictionaryTests : XCTestCase +@end + +@implementation GPBInt64Int32DictionaryTests + +- (void)testEmpty { + GPBInt64Int32Dictionary *dict = [[GPBInt64Int32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt64Int32Dictionary *dict = [GPBInt64Int32Dictionary dictionaryWithValue:200 forKey:21LL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 21LL); + XCTAssertEqual(aValue, 200); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int64_t kKeys[] = { 21LL, 22LL, 23LL }; + const int32_t kValues[] = { 200, 201, 202 }; + GPBInt64Int32Dictionary *dict = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + __block NSUInteger idx = 0; + int64_t *seenKeys = malloc(3 * sizeof(int64_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kKeys2[] = { 22LL, 21LL, 24LL }; + const int32_t kValues1[] = { 200, 201, 202 }; + const int32_t kValues2[] = { 200, 203, 202 }; + const int32_t kValues3[] = { 200, 201, 202, 203 }; + GPBInt64Int32Dictionary *dict1 = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt64Int32Dictionary *dict1prime = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt64Int32Dictionary *dict2 = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt64Int32Dictionary *dict3 = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt64Int32Dictionary *dict4 = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBInt64Int32Dictionary *dict = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64Int32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt64Int32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBInt64Int32Dictionary *dict = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64Int32Dictionary *dict2 = + [GPBInt64Int32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt64Int32Dictionary *dict = [GPBInt64Int32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:200 forKey:21LL]; + XCTAssertEqual(dict.count, 1U); + + const int64_t kKeys[] = { 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 201, 202, 203 }; + GPBInt64Int32Dictionary *dict2 = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 203); + [dict2 release]; +} + +- (void)testRemove { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBInt64Int32Dictionary *dict = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 203); + + // Remove again does nothing. + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 203); + + [dict removeValueForKey:24LL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertFalse([dict valueForKey:23LL value:NULL]); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBInt64Int32Dictionary *dict = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 203); + + [dict setValue:203 forKey:21LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 203); + + [dict setValue:201 forKey:24LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 201); + + const int64_t kKeys2[] = { 22LL, 23LL }; + const int32_t kValues2[] = { 202, 200 }; + GPBInt64Int32Dictionary *dict2 = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 201); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int64 -> UInt64 + +@interface GPBInt64UInt64DictionaryTests : XCTestCase +@end + +@implementation GPBInt64UInt64DictionaryTests + +- (void)testEmpty { + GPBInt64UInt64Dictionary *dict = [[GPBInt64UInt64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt64UInt64Dictionary *dict = [GPBInt64UInt64Dictionary dictionaryWithValue:300U forKey:21LL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint64_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint64_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 21LL); + XCTAssertEqual(aValue, 300U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int64_t kKeys[] = { 21LL, 22LL, 23LL }; + const uint64_t kValues[] = { 300U, 301U, 302U }; + GPBInt64UInt64Dictionary *dict = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + uint64_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + __block NSUInteger idx = 0; + int64_t *seenKeys = malloc(3 * sizeof(int64_t)); + uint64_t *seenValues = malloc(3 * sizeof(uint64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kKeys2[] = { 22LL, 21LL, 24LL }; + const uint64_t kValues1[] = { 300U, 301U, 302U }; + const uint64_t kValues2[] = { 300U, 303U, 302U }; + const uint64_t kValues3[] = { 300U, 301U, 302U, 303U }; + GPBInt64UInt64Dictionary *dict1 = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt64UInt64Dictionary *dict1prime = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt64UInt64Dictionary *dict2 = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt64UInt64Dictionary *dict3 = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt64UInt64Dictionary *dict4 = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBInt64UInt64Dictionary *dict = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64UInt64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt64UInt64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBInt64UInt64Dictionary *dict = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64UInt64Dictionary *dict2 = + [GPBInt64UInt64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt64UInt64Dictionary *dict = [GPBInt64UInt64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:300U forKey:21LL]; + XCTAssertEqual(dict.count, 1U); + + const int64_t kKeys[] = { 22LL, 23LL, 24LL }; + const uint64_t kValues[] = { 301U, 302U, 303U }; + GPBInt64UInt64Dictionary *dict2 = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + uint64_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 303U); + [dict2 release]; +} + +- (void)testRemove { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBInt64UInt64Dictionary *dict = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + uint64_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 303U); + + // Remove again does nothing. + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 303U); + + [dict removeValueForKey:24LL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertFalse([dict valueForKey:23LL value:NULL]); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBInt64UInt64Dictionary *dict = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + uint64_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 303U); + + [dict setValue:303U forKey:21LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 303U); + + [dict setValue:301U forKey:24LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 301U); + + const int64_t kKeys2[] = { 22LL, 23LL }; + const uint64_t kValues2[] = { 302U, 300U }; + GPBInt64UInt64Dictionary *dict2 = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 301U); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int64 -> Int64 + +@interface GPBInt64Int64DictionaryTests : XCTestCase +@end + +@implementation GPBInt64Int64DictionaryTests + +- (void)testEmpty { + GPBInt64Int64Dictionary *dict = [[GPBInt64Int64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt64Int64Dictionary *dict = [GPBInt64Int64Dictionary dictionaryWithValue:400 forKey:21LL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int64_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int64_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 21LL); + XCTAssertEqual(aValue, 400); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int64_t kKeys[] = { 21LL, 22LL, 23LL }; + const int64_t kValues[] = { 400, 401, 402 }; + GPBInt64Int64Dictionary *dict = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int64_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + __block NSUInteger idx = 0; + int64_t *seenKeys = malloc(3 * sizeof(int64_t)); + int64_t *seenValues = malloc(3 * sizeof(int64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kKeys2[] = { 22LL, 21LL, 24LL }; + const int64_t kValues1[] = { 400, 401, 402 }; + const int64_t kValues2[] = { 400, 403, 402 }; + const int64_t kValues3[] = { 400, 401, 402, 403 }; + GPBInt64Int64Dictionary *dict1 = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt64Int64Dictionary *dict1prime = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt64Int64Dictionary *dict2 = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt64Int64Dictionary *dict3 = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt64Int64Dictionary *dict4 = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBInt64Int64Dictionary *dict = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64Int64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt64Int64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBInt64Int64Dictionary *dict = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64Int64Dictionary *dict2 = + [GPBInt64Int64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt64Int64Dictionary *dict = [GPBInt64Int64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:400 forKey:21LL]; + XCTAssertEqual(dict.count, 1U); + + const int64_t kKeys[] = { 22LL, 23LL, 24LL }; + const int64_t kValues[] = { 401, 402, 403 }; + GPBInt64Int64Dictionary *dict2 = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int64_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 403); + [dict2 release]; +} + +- (void)testRemove { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBInt64Int64Dictionary *dict = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + int64_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 403); + + // Remove again does nothing. + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 403); + + [dict removeValueForKey:24LL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertFalse([dict valueForKey:23LL value:NULL]); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBInt64Int64Dictionary *dict = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int64_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 403); + + [dict setValue:403 forKey:21LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 403); + + [dict setValue:401 forKey:24LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 401); + + const int64_t kKeys2[] = { 22LL, 23LL }; + const int64_t kValues2[] = { 402, 400 }; + GPBInt64Int64Dictionary *dict2 = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 401); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int64 -> Bool + +@interface GPBInt64BoolDictionaryTests : XCTestCase +@end + +@implementation GPBInt64BoolDictionaryTests + +- (void)testEmpty { + GPBInt64BoolDictionary *dict = [[GPBInt64BoolDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt64BoolDictionary *dict = [GPBInt64BoolDictionary dictionaryWithValue:YES forKey:21LL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + BOOL value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, BOOL aValue, BOOL *stop) { + XCTAssertEqual(aKey, 21LL); + XCTAssertEqual(aValue, YES); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int64_t kKeys[] = { 21LL, 22LL, 23LL }; + const BOOL kValues[] = { YES, YES, NO }; + GPBInt64BoolDictionary *dict = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + BOOL value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + __block NSUInteger idx = 0; + int64_t *seenKeys = malloc(3 * sizeof(int64_t)); + BOOL *seenValues = malloc(3 * sizeof(BOOL)); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, BOOL aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kKeys2[] = { 22LL, 21LL, 24LL }; + const BOOL kValues1[] = { YES, YES, NO }; + const BOOL kValues2[] = { YES, NO, NO }; + const BOOL kValues3[] = { YES, YES, NO, NO }; + GPBInt64BoolDictionary *dict1 = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt64BoolDictionary *dict1prime = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt64BoolDictionary *dict2 = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt64BoolDictionary *dict3 = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt64BoolDictionary *dict4 = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBInt64BoolDictionary *dict = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64BoolDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt64BoolDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBInt64BoolDictionary *dict = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64BoolDictionary *dict2 = + [GPBInt64BoolDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt64BoolDictionary *dict = [GPBInt64BoolDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:YES forKey:21LL]; + XCTAssertEqual(dict.count, 1U); + + const int64_t kKeys[] = { 22LL, 23LL, 24LL }; + const BOOL kValues[] = { YES, NO, NO }; + GPBInt64BoolDictionary *dict2 = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + BOOL value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, NO); + [dict2 release]; +} + +- (void)testRemove { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBInt64BoolDictionary *dict = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + BOOL value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, NO); + + // Remove again does nothing. + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, NO); + + [dict removeValueForKey:24LL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertFalse([dict valueForKey:23LL value:NULL]); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBInt64BoolDictionary *dict = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + BOOL value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, NO); + + [dict setValue:NO forKey:21LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, NO); + + [dict setValue:YES forKey:24LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, YES); + + const int64_t kKeys2[] = { 22LL, 23LL }; + const BOOL kValues2[] = { NO, YES }; + GPBInt64BoolDictionary *dict2 = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, YES); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int64 -> Float + +@interface GPBInt64FloatDictionaryTests : XCTestCase +@end + +@implementation GPBInt64FloatDictionaryTests + +- (void)testEmpty { + GPBInt64FloatDictionary *dict = [[GPBInt64FloatDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt64FloatDictionary *dict = [GPBInt64FloatDictionary dictionaryWithValue:500.f forKey:21LL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + float value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, float aValue, BOOL *stop) { + XCTAssertEqual(aKey, 21LL); + XCTAssertEqual(aValue, 500.f); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int64_t kKeys[] = { 21LL, 22LL, 23LL }; + const float kValues[] = { 500.f, 501.f, 502.f }; + GPBInt64FloatDictionary *dict = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + float value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + __block NSUInteger idx = 0; + int64_t *seenKeys = malloc(3 * sizeof(int64_t)); + float *seenValues = malloc(3 * sizeof(float)); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, float aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kKeys2[] = { 22LL, 21LL, 24LL }; + const float kValues1[] = { 500.f, 501.f, 502.f }; + const float kValues2[] = { 500.f, 503.f, 502.f }; + const float kValues3[] = { 500.f, 501.f, 502.f, 503.f }; + GPBInt64FloatDictionary *dict1 = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt64FloatDictionary *dict1prime = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt64FloatDictionary *dict2 = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt64FloatDictionary *dict3 = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt64FloatDictionary *dict4 = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBInt64FloatDictionary *dict = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64FloatDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt64FloatDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBInt64FloatDictionary *dict = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64FloatDictionary *dict2 = + [GPBInt64FloatDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt64FloatDictionary *dict = [GPBInt64FloatDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:500.f forKey:21LL]; + XCTAssertEqual(dict.count, 1U); + + const int64_t kKeys[] = { 22LL, 23LL, 24LL }; + const float kValues[] = { 501.f, 502.f, 503.f }; + GPBInt64FloatDictionary *dict2 = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + float value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 503.f); + [dict2 release]; +} + +- (void)testRemove { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBInt64FloatDictionary *dict = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + float value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 503.f); + + // Remove again does nothing. + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 503.f); + + [dict removeValueForKey:24LL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertFalse([dict valueForKey:23LL value:NULL]); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBInt64FloatDictionary *dict = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + float value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 503.f); + + [dict setValue:503.f forKey:21LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 503.f); + + [dict setValue:501.f forKey:24LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 501.f); + + const int64_t kKeys2[] = { 22LL, 23LL }; + const float kValues2[] = { 502.f, 500.f }; + GPBInt64FloatDictionary *dict2 = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 501.f); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int64 -> Double + +@interface GPBInt64DoubleDictionaryTests : XCTestCase +@end + +@implementation GPBInt64DoubleDictionaryTests + +- (void)testEmpty { + GPBInt64DoubleDictionary *dict = [[GPBInt64DoubleDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt64DoubleDictionary *dict = [GPBInt64DoubleDictionary dictionaryWithValue:600. forKey:21LL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + double value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, double aValue, BOOL *stop) { + XCTAssertEqual(aKey, 21LL); + XCTAssertEqual(aValue, 600.); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int64_t kKeys[] = { 21LL, 22LL, 23LL }; + const double kValues[] = { 600., 601., 602. }; + GPBInt64DoubleDictionary *dict = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + double value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + __block NSUInteger idx = 0; + int64_t *seenKeys = malloc(3 * sizeof(int64_t)); + double *seenValues = malloc(3 * sizeof(double)); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, double aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kKeys2[] = { 22LL, 21LL, 24LL }; + const double kValues1[] = { 600., 601., 602. }; + const double kValues2[] = { 600., 603., 602. }; + const double kValues3[] = { 600., 601., 602., 603. }; + GPBInt64DoubleDictionary *dict1 = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt64DoubleDictionary *dict1prime = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt64DoubleDictionary *dict2 = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt64DoubleDictionary *dict3 = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt64DoubleDictionary *dict4 = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBInt64DoubleDictionary *dict = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64DoubleDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt64DoubleDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBInt64DoubleDictionary *dict = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64DoubleDictionary *dict2 = + [GPBInt64DoubleDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt64DoubleDictionary *dict = [GPBInt64DoubleDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:600. forKey:21LL]; + XCTAssertEqual(dict.count, 1U); + + const int64_t kKeys[] = { 22LL, 23LL, 24LL }; + const double kValues[] = { 601., 602., 603. }; + GPBInt64DoubleDictionary *dict2 = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + double value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 603.); + [dict2 release]; +} + +- (void)testRemove { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBInt64DoubleDictionary *dict = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + double value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 603.); + + // Remove again does nothing. + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 603.); + + [dict removeValueForKey:24LL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertFalse([dict valueForKey:23LL value:NULL]); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBInt64DoubleDictionary *dict = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + double value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 603.); + + [dict setValue:603. forKey:21LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 603.); + + [dict setValue:601. forKey:24LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 601.); + + const int64_t kKeys2[] = { 22LL, 23LL }; + const double kValues2[] = { 602., 600. }; + GPBInt64DoubleDictionary *dict2 = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 601.); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int64 -> Enum + +@interface GPBInt64EnumDictionaryTests : XCTestCase +@end + +@implementation GPBInt64EnumDictionaryTests + +- (void)testEmpty { + GPBInt64EnumDictionary *dict = [[GPBInt64EnumDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt64EnumDictionary *dict = [GPBInt64EnumDictionary dictionaryWithValue:700 forKey:21LL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 21LL); + XCTAssertEqual(aValue, 700); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int64_t kKeys[] = { 21LL, 22LL, 23LL }; + const int32_t kValues[] = { 700, 701, 702 }; + GPBInt64EnumDictionary *dict = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + __block NSUInteger idx = 0; + int64_t *seenKeys = malloc(3 * sizeof(int64_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kKeys2[] = { 22LL, 21LL, 24LL }; + const int32_t kValues1[] = { 700, 701, 702 }; + const int32_t kValues2[] = { 700, 703, 702 }; + const int32_t kValues3[] = { 700, 701, 702, 703 }; + GPBInt64EnumDictionary *dict1 = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt64EnumDictionary *dict1prime = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt64EnumDictionary *dict2 = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt64EnumDictionary *dict3 = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt64EnumDictionary *dict4 = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBInt64EnumDictionary *dict = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt64EnumDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBInt64EnumDictionary *dict = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64EnumDictionary *dict2 = + [GPBInt64EnumDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt64EnumDictionary *dict = [GPBInt64EnumDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:700 forKey:21LL]; + XCTAssertEqual(dict.count, 1U); + + const int64_t kKeys[] = { 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 701, 702, 703 }; + GPBInt64EnumDictionary *dict2 = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 703); + [dict2 release]; +} + +- (void)testRemove { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBInt64EnumDictionary *dict = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 703); + + // Remove again does nothing. + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 703); + + [dict removeValueForKey:24LL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertFalse([dict valueForKey:23LL value:NULL]); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBInt64EnumDictionary *dict = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 703); + + [dict setValue:703 forKey:21LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 703); + + [dict setValue:701 forKey:24LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 701); + + const int64_t kKeys2[] = { 22LL, 23LL }; + const int32_t kValues2[] = { 702, 700 }; + GPBInt64EnumDictionary *dict2 = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 701); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int64 -> Enum (Unknown Enums) + +@interface GPBInt64EnumDictionaryUnknownEnumTests : XCTestCase +@end + +@implementation GPBInt64EnumDictionaryUnknownEnumTests + +- (void)testRawBasics { + const int64_t kKeys[] = { 21LL, 22LL, 23LL }; + const int32_t kValues[] = { 700, 801, 702 }; + GPBInt64EnumDictionary *dict = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue(dict.validationFunc == TestingEnum_IsValidValue); // Pointer comparison + int32_t value; + XCTAssertTrue([dict valueForKey:21LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:21LL rawValue:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:22LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:22LL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:23LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:23LL rawValue:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:24LL rawValue:NULL]); + + __block NSUInteger idx = 0; + int64_t *seenKeys = malloc(3 * sizeof(int64_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + if (i == 1) { + XCTAssertEqual(kGPBUnrecognizedEnumeratorValue, seenValues[j], @"i = %d, j = %d", i, j); + } else { + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + idx = 0; + [dict enumerateKeysAndRawValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndRawValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEqualityWithUnknowns { + const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kKeys2[] = { 22LL, 21LL, 24LL }; + const int32_t kValues1[] = { 700, 801, 702 }; // Unknown + const int32_t kValues2[] = { 700, 803, 702 }; // Unknown + const int32_t kValues3[] = { 700, 801, 702, 803 }; // Unknowns + GPBInt64EnumDictionary *dict1 = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt64EnumDictionary *dict1prime = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt64EnumDictionary *dict2 = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt64EnumDictionary *dict3 = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt64EnumDictionary *dict4 = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopyWithUnknowns { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknown + GPBInt64EnumDictionary *dict = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + XCTAssertEqualObjects(dict, dict2); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBInt64EnumDictionary *dict = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64EnumDictionary *dict2 = + [GPBInt64EnumDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + [dict release]; +} + +- (void)testUnknownAdds { + GPBInt64EnumDictionary *dict = + [GPBInt64EnumDictionary dictionaryWithValidationFunction:TestingEnum_IsValidValue]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + XCTAssertThrowsSpecificNamed([dict setValue:801 forKey:22LL], // Unknown + NSException, NSInvalidArgumentException); + XCTAssertEqual(dict.count, 0U); + [dict setRawValue:801 forKey:22LL]; // Unknown + XCTAssertEqual(dict.count, 1U); + + const int64_t kKeys[] = { 21LL, 23LL, 24LL }; + const int32_t kValues[] = { 700, 702, 803 }; // Unknown + GPBInt64EnumDictionary *dict2 = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:22LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:22LL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:24LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:24LL rawValue:&value]); + XCTAssertEqual(value, 803); + [dict2 release]; +} + +- (void)testUnknownRemove { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBInt64EnumDictionary *dict = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:24LL rawValue:&value]); + XCTAssertEqual(value, 803); + + // Remove again does nothing. + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:24LL rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict removeValueForKey:24LL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertFalse([dict valueForKey:23LL value:NULL]); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutationUnknowns { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBInt64EnumDictionary *dict = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:22LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:22LL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:24LL rawValue:&value]); + XCTAssertEqual(value, 803); + + XCTAssertThrowsSpecificNamed([dict setValue:803 forKey:21LL], // Unknown + NSException, NSInvalidArgumentException); + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:22LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:22LL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:24LL rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict setRawValue:803 forKey:21LL]; // Unknown + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:21LL rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:22LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:22LL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:24LL rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict setRawValue:700 forKey:24LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:21LL rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:22LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:22LL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 700); + + const int64_t kKeys2[] = { 22LL, 23LL }; + const int32_t kValues2[] = { 702, 801 }; // Unknown + GPBInt64EnumDictionary *dict2 = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:21LL rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:23LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:23LL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 700); + + [dict2 release]; + [dict release]; +} + +- (void)testCopyUnknowns { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 700, 801, 702, 803 }; + GPBInt64EnumDictionary *dict = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + XCTAssertTrue([dict2 isKindOfClass:[GPBInt64EnumDictionary class]]); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int64 -> Object + +@interface GPBInt64ObjectDictionaryTests : XCTestCase +@end + +@implementation GPBInt64ObjectDictionaryTests + +- (void)testEmpty { + GPBInt64ObjectDictionary *dict = [[GPBInt64ObjectDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertNil([dict valueForKey:21LL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, id aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt64ObjectDictionary *dict = [GPBInt64ObjectDictionary dictionaryWithValue:@"abc" forKey:21LL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + XCTAssertEqualObjects([dict valueForKey:21LL], @"abc"); + XCTAssertNil([dict valueForKey:22LL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, id aValue, BOOL *stop) { + XCTAssertEqual(aKey, 21LL); + XCTAssertEqualObjects(aValue, @"abc"); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int64_t kKeys[] = { 21LL, 22LL, 23LL }; + const id kValues[] = { @"abc", @"def", @"ghi" }; + GPBInt64ObjectDictionary *dict = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:21LL], @"abc"); + XCTAssertEqualObjects([dict valueForKey:22LL], @"def"); + XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi"); + XCTAssertNil([dict valueForKey:24LL]); + + __block NSUInteger idx = 0; + int64_t *seenKeys = malloc(3 * sizeof(int64_t)); + id *seenValues = malloc(3 * sizeof(id)); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, id aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqualObjects(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, id aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kKeys2[] = { 22LL, 21LL, 24LL }; + const id kValues1[] = { @"abc", @"def", @"ghi" }; + const id kValues2[] = { @"abc", @"jkl", @"ghi" }; + const id kValues3[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBInt64ObjectDictionary *dict1 = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt64ObjectDictionary *dict1prime = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt64ObjectDictionary *dict2 = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt64ObjectDictionary *dict3 = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt64ObjectDictionary *dict4 = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBInt64ObjectDictionary *dict = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64ObjectDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt64ObjectDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBInt64ObjectDictionary *dict = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64ObjectDictionary *dict2 = + [GPBInt64ObjectDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt64ObjectDictionary *dict = [GPBInt64ObjectDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:@"abc" forKey:21LL]; + XCTAssertEqual(dict.count, 1U); + + const int64_t kKeys[] = { 22LL, 23LL, 24LL }; + const id kValues[] = { @"def", @"ghi", @"jkl" }; + GPBInt64ObjectDictionary *dict2 = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + XCTAssertEqualObjects([dict valueForKey:21LL], @"abc"); + XCTAssertEqualObjects([dict valueForKey:22LL], @"def"); + XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:24LL], @"jkl"); + [dict2 release]; +} + +- (void)testRemove { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBInt64ObjectDictionary *dict = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:21LL], @"abc"); + XCTAssertNil([dict valueForKey:22LL]); + XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:24LL], @"jkl"); + + // Remove again does nothing. + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:21LL], @"abc"); + XCTAssertNil([dict valueForKey:22LL]); + XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:24LL], @"jkl"); + + [dict removeValueForKey:24LL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertEqualObjects([dict valueForKey:21LL], @"abc"); + XCTAssertNil([dict valueForKey:22LL]); + XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi"); + XCTAssertNil([dict valueForKey:24LL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertNil([dict valueForKey:21LL]); + XCTAssertNil([dict valueForKey:22LL]); + XCTAssertNil([dict valueForKey:23LL]); + XCTAssertNil([dict valueForKey:24LL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBInt64ObjectDictionary *dict = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:21LL], @"abc"); + XCTAssertEqualObjects([dict valueForKey:22LL], @"def"); + XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:24LL], @"jkl"); + + [dict setValue:@"jkl" forKey:21LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:21LL], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:22LL], @"def"); + XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:24LL], @"jkl"); + + [dict setValue:@"def" forKey:24LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:21LL], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:22LL], @"def"); + XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:24LL], @"def"); + + const int64_t kKeys2[] = { 22LL, 23LL }; + const id kValues2[] = { @"ghi", @"abc" }; + GPBInt64ObjectDictionary *dict2 = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:21LL], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:22LL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:23LL], @"abc"); + XCTAssertEqualObjects([dict valueForKey:24LL], @"def"); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND-END TEST_FOR_POD_KEY(Int64, int64_t, 21LL, 22LL, 23LL, 24LL) + diff --git a/objectivec/Tests/GPBDictionaryTests+String.m b/objectivec/Tests/GPBDictionaryTests+String.m new file mode 100644 index 00000000..95bf2d06 --- /dev/null +++ b/objectivec/Tests/GPBDictionaryTests+String.m @@ -0,0 +1,3362 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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. + +#import <Foundation/Foundation.h> +#import <XCTest/XCTest.h> + +#import "GPBDictionary.h" + +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h" + +// Pull in the macros (using an external file because expanding all tests +// in a single file makes a file that is failing to work with within Xcode. +//%PDDM-IMPORT-DEFINES GPBDictionaryTests.pddm + +//%PDDM-EXPAND TESTS_FOR_POD_VALUES(String, NSString, *, Objects, @"foo", @"bar", @"baz", @"mumble") +// This block of code is generated, do not edit it directly. + +#ifndef GPBARRAYSIZE +#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0])))) +#endif // GPBARRAYSIZE + +// To let the testing macros work, add some extra methods to simplify things. +@interface GPBStringEnumDictionary (TestingTweak) ++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(NSString *)key; +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const NSString * [])keys + count:(NSUInteger)count; +@end + +static BOOL TestingEnum_IsValidValue(int32_t value) { + switch (value) { + case 700: + case 701: + case 702: + case 703: + return YES; + default: + return NO; + } +} + +@implementation GPBStringEnumDictionary (TestingTweak) ++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(NSString *)key { + // Cast is needed to compiler knows what class we are invoking initWithValues: on to get the + // type correct. + return [[(GPBStringEnumDictionary*)[self alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:&value + forKeys:&key + count:1] autorelease]; +} +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const NSString * [])keys + count:(NSUInteger)count { + return [self initWithValidationFunction:TestingEnum_IsValidValue + rawValues:values + forKeys:keys + count:count]; +} +@end + + +#pragma mark - String -> UInt32 + +@interface GPBStringUInt32DictionaryTests : XCTestCase +@end + +@implementation GPBStringUInt32DictionaryTests + +- (void)testEmpty { + GPBStringUInt32Dictionary *dict = [[GPBStringUInt32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBStringUInt32Dictionary *dict = [GPBStringUInt32Dictionary dictionaryWithValue:100U forKey:@"foo"]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint32_t aValue, BOOL *stop) { + XCTAssertEqualObjects(aKey, @"foo"); + XCTAssertEqual(aValue, 100U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const NSString *kKeys[] = { @"foo", @"bar", @"baz" }; + const uint32_t kValues[] = { 100U, 101U, 102U }; + GPBStringUInt32Dictionary *dict = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + uint32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + __block NSUInteger idx = 0; + NSString **seenKeys = malloc(3 * sizeof(NSString*)); + uint32_t *seenValues = malloc(3 * sizeof(uint32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if ([kKeys[i] isEqual:seenKeys[j]]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" }; + const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" }; + const uint32_t kValues1[] = { 100U, 101U, 102U }; + const uint32_t kValues2[] = { 100U, 103U, 102U }; + const uint32_t kValues3[] = { 100U, 101U, 102U, 103U }; + GPBStringUInt32Dictionary *dict1 = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBStringUInt32Dictionary *dict1prime = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBStringUInt32Dictionary *dict2 = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBStringUInt32Dictionary *dict3 = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBStringUInt32Dictionary *dict4 = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBStringUInt32Dictionary *dict = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringUInt32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBStringUInt32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBStringUInt32Dictionary *dict = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringUInt32Dictionary *dict2 = + [GPBStringUInt32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBStringUInt32Dictionary *dict = [GPBStringUInt32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:100U forKey:@"foo"]; + XCTAssertEqual(dict.count, 1U); + + const NSString *kKeys[] = { @"bar", @"baz", @"mumble" }; + const uint32_t kValues[] = { 101U, 102U, 103U }; + GPBStringUInt32Dictionary *dict2 = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + uint32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 103U); + [dict2 release]; +} + +- (void)testRemove { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBStringUInt32Dictionary *dict = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + uint32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 103U); + + // Remove again does nothing. + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 103U); + + [dict removeValueForKey:@"mumble"]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertFalse([dict valueForKey:@"baz" value:NULL]); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBStringUInt32Dictionary *dict = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + uint32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 103U); + + [dict setValue:103U forKey:@"foo"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 103U); + + [dict setValue:101U forKey:@"mumble"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 101U); + + const NSString *kKeys2[] = { @"bar", @"baz" }; + const uint32_t kValues2[] = { 102U, 100U }; + GPBStringUInt32Dictionary *dict2 = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 101U); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - String -> Int32 + +@interface GPBStringInt32DictionaryTests : XCTestCase +@end + +@implementation GPBStringInt32DictionaryTests + +- (void)testEmpty { + GPBStringInt32Dictionary *dict = [[GPBStringInt32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBStringInt32Dictionary *dict = [GPBStringInt32Dictionary dictionaryWithValue:200 forKey:@"foo"]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) { + XCTAssertEqualObjects(aKey, @"foo"); + XCTAssertEqual(aValue, 200); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const NSString *kKeys[] = { @"foo", @"bar", @"baz" }; + const int32_t kValues[] = { 200, 201, 202 }; + GPBStringInt32Dictionary *dict = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 202); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + __block NSUInteger idx = 0; + NSString **seenKeys = malloc(3 * sizeof(NSString*)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if ([kKeys[i] isEqual:seenKeys[j]]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" }; + const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" }; + const int32_t kValues1[] = { 200, 201, 202 }; + const int32_t kValues2[] = { 200, 203, 202 }; + const int32_t kValues3[] = { 200, 201, 202, 203 }; + GPBStringInt32Dictionary *dict1 = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBStringInt32Dictionary *dict1prime = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBStringInt32Dictionary *dict2 = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBStringInt32Dictionary *dict3 = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBStringInt32Dictionary *dict4 = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBStringInt32Dictionary *dict = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringInt32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBStringInt32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBStringInt32Dictionary *dict = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringInt32Dictionary *dict2 = + [GPBStringInt32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBStringInt32Dictionary *dict = [GPBStringInt32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:200 forKey:@"foo"]; + XCTAssertEqual(dict.count, 1U); + + const NSString *kKeys[] = { @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 201, 202, 203 }; + GPBStringInt32Dictionary *dict2 = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 203); + [dict2 release]; +} + +- (void)testRemove { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBStringInt32Dictionary *dict = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 203); + + // Remove again does nothing. + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 203); + + [dict removeValueForKey:@"mumble"]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 202); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertFalse([dict valueForKey:@"baz" value:NULL]); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBStringInt32Dictionary *dict = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 203); + + [dict setValue:203 forKey:@"foo"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 203); + + [dict setValue:201 forKey:@"mumble"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 201); + + const NSString *kKeys2[] = { @"bar", @"baz" }; + const int32_t kValues2[] = { 202, 200 }; + GPBStringInt32Dictionary *dict2 = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 201); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - String -> UInt64 + +@interface GPBStringUInt64DictionaryTests : XCTestCase +@end + +@implementation GPBStringUInt64DictionaryTests + +- (void)testEmpty { + GPBStringUInt64Dictionary *dict = [[GPBStringUInt64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBStringUInt64Dictionary *dict = [GPBStringUInt64Dictionary dictionaryWithValue:300U forKey:@"foo"]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint64_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint64_t aValue, BOOL *stop) { + XCTAssertEqualObjects(aKey, @"foo"); + XCTAssertEqual(aValue, 300U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const NSString *kKeys[] = { @"foo", @"bar", @"baz" }; + const uint64_t kValues[] = { 300U, 301U, 302U }; + GPBStringUInt64Dictionary *dict = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + uint64_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + __block NSUInteger idx = 0; + NSString **seenKeys = malloc(3 * sizeof(NSString*)); + uint64_t *seenValues = malloc(3 * sizeof(uint64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if ([kKeys[i] isEqual:seenKeys[j]]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" }; + const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" }; + const uint64_t kValues1[] = { 300U, 301U, 302U }; + const uint64_t kValues2[] = { 300U, 303U, 302U }; + const uint64_t kValues3[] = { 300U, 301U, 302U, 303U }; + GPBStringUInt64Dictionary *dict1 = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBStringUInt64Dictionary *dict1prime = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBStringUInt64Dictionary *dict2 = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBStringUInt64Dictionary *dict3 = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBStringUInt64Dictionary *dict4 = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBStringUInt64Dictionary *dict = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringUInt64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBStringUInt64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBStringUInt64Dictionary *dict = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringUInt64Dictionary *dict2 = + [GPBStringUInt64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBStringUInt64Dictionary *dict = [GPBStringUInt64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:300U forKey:@"foo"]; + XCTAssertEqual(dict.count, 1U); + + const NSString *kKeys[] = { @"bar", @"baz", @"mumble" }; + const uint64_t kValues[] = { 301U, 302U, 303U }; + GPBStringUInt64Dictionary *dict2 = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + uint64_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 303U); + [dict2 release]; +} + +- (void)testRemove { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBStringUInt64Dictionary *dict = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + uint64_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 303U); + + // Remove again does nothing. + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 303U); + + [dict removeValueForKey:@"mumble"]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertFalse([dict valueForKey:@"baz" value:NULL]); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBStringUInt64Dictionary *dict = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + uint64_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 303U); + + [dict setValue:303U forKey:@"foo"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 303U); + + [dict setValue:301U forKey:@"mumble"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 301U); + + const NSString *kKeys2[] = { @"bar", @"baz" }; + const uint64_t kValues2[] = { 302U, 300U }; + GPBStringUInt64Dictionary *dict2 = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 301U); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - String -> Int64 + +@interface GPBStringInt64DictionaryTests : XCTestCase +@end + +@implementation GPBStringInt64DictionaryTests + +- (void)testEmpty { + GPBStringInt64Dictionary *dict = [[GPBStringInt64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBStringInt64Dictionary *dict = [GPBStringInt64Dictionary dictionaryWithValue:400 forKey:@"foo"]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int64_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int64_t aValue, BOOL *stop) { + XCTAssertEqualObjects(aKey, @"foo"); + XCTAssertEqual(aValue, 400); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const NSString *kKeys[] = { @"foo", @"bar", @"baz" }; + const int64_t kValues[] = { 400, 401, 402 }; + GPBStringInt64Dictionary *dict = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int64_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 402); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + __block NSUInteger idx = 0; + NSString **seenKeys = malloc(3 * sizeof(NSString*)); + int64_t *seenValues = malloc(3 * sizeof(int64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if ([kKeys[i] isEqual:seenKeys[j]]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" }; + const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" }; + const int64_t kValues1[] = { 400, 401, 402 }; + const int64_t kValues2[] = { 400, 403, 402 }; + const int64_t kValues3[] = { 400, 401, 402, 403 }; + GPBStringInt64Dictionary *dict1 = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBStringInt64Dictionary *dict1prime = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBStringInt64Dictionary *dict2 = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBStringInt64Dictionary *dict3 = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBStringInt64Dictionary *dict4 = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBStringInt64Dictionary *dict = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringInt64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBStringInt64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBStringInt64Dictionary *dict = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringInt64Dictionary *dict2 = + [GPBStringInt64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBStringInt64Dictionary *dict = [GPBStringInt64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:400 forKey:@"foo"]; + XCTAssertEqual(dict.count, 1U); + + const NSString *kKeys[] = { @"bar", @"baz", @"mumble" }; + const int64_t kValues[] = { 401, 402, 403 }; + GPBStringInt64Dictionary *dict2 = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int64_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 403); + [dict2 release]; +} + +- (void)testRemove { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBStringInt64Dictionary *dict = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + int64_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 403); + + // Remove again does nothing. + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 403); + + [dict removeValueForKey:@"mumble"]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 402); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertFalse([dict valueForKey:@"baz" value:NULL]); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBStringInt64Dictionary *dict = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int64_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 403); + + [dict setValue:403 forKey:@"foo"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 403); + + [dict setValue:401 forKey:@"mumble"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 401); + + const NSString *kKeys2[] = { @"bar", @"baz" }; + const int64_t kValues2[] = { 402, 400 }; + GPBStringInt64Dictionary *dict2 = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 401); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - String -> Bool + +@interface GPBStringBoolDictionaryTests : XCTestCase +@end + +@implementation GPBStringBoolDictionaryTests + +- (void)testEmpty { + GPBStringBoolDictionary *dict = [[GPBStringBoolDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBStringBoolDictionary *dict = [GPBStringBoolDictionary dictionaryWithValue:YES forKey:@"foo"]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + BOOL value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, BOOL aValue, BOOL *stop) { + XCTAssertEqualObjects(aKey, @"foo"); + XCTAssertEqual(aValue, YES); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const NSString *kKeys[] = { @"foo", @"bar", @"baz" }; + const BOOL kValues[] = { YES, YES, NO }; + GPBStringBoolDictionary *dict = + [[GPBStringBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + BOOL value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + __block NSUInteger idx = 0; + NSString **seenKeys = malloc(3 * sizeof(NSString*)); + BOOL *seenValues = malloc(3 * sizeof(BOOL)); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, BOOL aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if ([kKeys[i] isEqual:seenKeys[j]]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" }; + const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" }; + const BOOL kValues1[] = { YES, YES, NO }; + const BOOL kValues2[] = { YES, NO, NO }; + const BOOL kValues3[] = { YES, YES, NO, NO }; + GPBStringBoolDictionary *dict1 = + [[GPBStringBoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBStringBoolDictionary *dict1prime = + [[GPBStringBoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBStringBoolDictionary *dict2 = + [[GPBStringBoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBStringBoolDictionary *dict3 = + [[GPBStringBoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBStringBoolDictionary *dict4 = + [[GPBStringBoolDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBStringBoolDictionary *dict = + [[GPBStringBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringBoolDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBStringBoolDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBStringBoolDictionary *dict = + [[GPBStringBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringBoolDictionary *dict2 = + [GPBStringBoolDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBStringBoolDictionary *dict = [GPBStringBoolDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:YES forKey:@"foo"]; + XCTAssertEqual(dict.count, 1U); + + const NSString *kKeys[] = { @"bar", @"baz", @"mumble" }; + const BOOL kValues[] = { YES, NO, NO }; + GPBStringBoolDictionary *dict2 = + [[GPBStringBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + BOOL value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, NO); + [dict2 release]; +} + +- (void)testRemove { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBStringBoolDictionary *dict = + [[GPBStringBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + BOOL value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, NO); + + // Remove again does nothing. + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, NO); + + [dict removeValueForKey:@"mumble"]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertFalse([dict valueForKey:@"baz" value:NULL]); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBStringBoolDictionary *dict = + [[GPBStringBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + BOOL value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, NO); + + [dict setValue:NO forKey:@"foo"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, NO); + + [dict setValue:YES forKey:@"mumble"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, YES); + + const NSString *kKeys2[] = { @"bar", @"baz" }; + const BOOL kValues2[] = { NO, YES }; + GPBStringBoolDictionary *dict2 = + [[GPBStringBoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, YES); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - String -> Float + +@interface GPBStringFloatDictionaryTests : XCTestCase +@end + +@implementation GPBStringFloatDictionaryTests + +- (void)testEmpty { + GPBStringFloatDictionary *dict = [[GPBStringFloatDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBStringFloatDictionary *dict = [GPBStringFloatDictionary dictionaryWithValue:500.f forKey:@"foo"]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + float value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, float aValue, BOOL *stop) { + XCTAssertEqualObjects(aKey, @"foo"); + XCTAssertEqual(aValue, 500.f); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const NSString *kKeys[] = { @"foo", @"bar", @"baz" }; + const float kValues[] = { 500.f, 501.f, 502.f }; + GPBStringFloatDictionary *dict = + [[GPBStringFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + float value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + __block NSUInteger idx = 0; + NSString **seenKeys = malloc(3 * sizeof(NSString*)); + float *seenValues = malloc(3 * sizeof(float)); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, float aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if ([kKeys[i] isEqual:seenKeys[j]]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" }; + const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" }; + const float kValues1[] = { 500.f, 501.f, 502.f }; + const float kValues2[] = { 500.f, 503.f, 502.f }; + const float kValues3[] = { 500.f, 501.f, 502.f, 503.f }; + GPBStringFloatDictionary *dict1 = + [[GPBStringFloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBStringFloatDictionary *dict1prime = + [[GPBStringFloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBStringFloatDictionary *dict2 = + [[GPBStringFloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBStringFloatDictionary *dict3 = + [[GPBStringFloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBStringFloatDictionary *dict4 = + [[GPBStringFloatDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBStringFloatDictionary *dict = + [[GPBStringFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringFloatDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBStringFloatDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBStringFloatDictionary *dict = + [[GPBStringFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringFloatDictionary *dict2 = + [GPBStringFloatDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBStringFloatDictionary *dict = [GPBStringFloatDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:500.f forKey:@"foo"]; + XCTAssertEqual(dict.count, 1U); + + const NSString *kKeys[] = { @"bar", @"baz", @"mumble" }; + const float kValues[] = { 501.f, 502.f, 503.f }; + GPBStringFloatDictionary *dict2 = + [[GPBStringFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + float value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 503.f); + [dict2 release]; +} + +- (void)testRemove { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBStringFloatDictionary *dict = + [[GPBStringFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + float value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 503.f); + + // Remove again does nothing. + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 503.f); + + [dict removeValueForKey:@"mumble"]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertFalse([dict valueForKey:@"baz" value:NULL]); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBStringFloatDictionary *dict = + [[GPBStringFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + float value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 503.f); + + [dict setValue:503.f forKey:@"foo"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 503.f); + + [dict setValue:501.f forKey:@"mumble"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 501.f); + + const NSString *kKeys2[] = { @"bar", @"baz" }; + const float kValues2[] = { 502.f, 500.f }; + GPBStringFloatDictionary *dict2 = + [[GPBStringFloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 501.f); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - String -> Double + +@interface GPBStringDoubleDictionaryTests : XCTestCase +@end + +@implementation GPBStringDoubleDictionaryTests + +- (void)testEmpty { + GPBStringDoubleDictionary *dict = [[GPBStringDoubleDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBStringDoubleDictionary *dict = [GPBStringDoubleDictionary dictionaryWithValue:600. forKey:@"foo"]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + double value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, double aValue, BOOL *stop) { + XCTAssertEqualObjects(aKey, @"foo"); + XCTAssertEqual(aValue, 600.); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const NSString *kKeys[] = { @"foo", @"bar", @"baz" }; + const double kValues[] = { 600., 601., 602. }; + GPBStringDoubleDictionary *dict = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + double value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + __block NSUInteger idx = 0; + NSString **seenKeys = malloc(3 * sizeof(NSString*)); + double *seenValues = malloc(3 * sizeof(double)); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, double aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if ([kKeys[i] isEqual:seenKeys[j]]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" }; + const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" }; + const double kValues1[] = { 600., 601., 602. }; + const double kValues2[] = { 600., 603., 602. }; + const double kValues3[] = { 600., 601., 602., 603. }; + GPBStringDoubleDictionary *dict1 = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBStringDoubleDictionary *dict1prime = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBStringDoubleDictionary *dict2 = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBStringDoubleDictionary *dict3 = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBStringDoubleDictionary *dict4 = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBStringDoubleDictionary *dict = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringDoubleDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBStringDoubleDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBStringDoubleDictionary *dict = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringDoubleDictionary *dict2 = + [GPBStringDoubleDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBStringDoubleDictionary *dict = [GPBStringDoubleDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:600. forKey:@"foo"]; + XCTAssertEqual(dict.count, 1U); + + const NSString *kKeys[] = { @"bar", @"baz", @"mumble" }; + const double kValues[] = { 601., 602., 603. }; + GPBStringDoubleDictionary *dict2 = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + double value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 603.); + [dict2 release]; +} + +- (void)testRemove { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBStringDoubleDictionary *dict = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + double value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 603.); + + // Remove again does nothing. + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 603.); + + [dict removeValueForKey:@"mumble"]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertFalse([dict valueForKey:@"baz" value:NULL]); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBStringDoubleDictionary *dict = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + double value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 603.); + + [dict setValue:603. forKey:@"foo"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 603.); + + [dict setValue:601. forKey:@"mumble"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 601.); + + const NSString *kKeys2[] = { @"bar", @"baz" }; + const double kValues2[] = { 602., 600. }; + GPBStringDoubleDictionary *dict2 = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 601.); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - String -> Enum + +@interface GPBStringEnumDictionaryTests : XCTestCase +@end + +@implementation GPBStringEnumDictionaryTests + +- (void)testEmpty { + GPBStringEnumDictionary *dict = [[GPBStringEnumDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBStringEnumDictionary *dict = [GPBStringEnumDictionary dictionaryWithValue:700 forKey:@"foo"]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) { + XCTAssertEqualObjects(aKey, @"foo"); + XCTAssertEqual(aValue, 700); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const NSString *kKeys[] = { @"foo", @"bar", @"baz" }; + const int32_t kValues[] = { 700, 701, 702 }; + GPBStringEnumDictionary *dict = + [[GPBStringEnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + __block NSUInteger idx = 0; + NSString **seenKeys = malloc(3 * sizeof(NSString*)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if ([kKeys[i] isEqual:seenKeys[j]]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" }; + const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" }; + const int32_t kValues1[] = { 700, 701, 702 }; + const int32_t kValues2[] = { 700, 703, 702 }; + const int32_t kValues3[] = { 700, 701, 702, 703 }; + GPBStringEnumDictionary *dict1 = + [[GPBStringEnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBStringEnumDictionary *dict1prime = + [[GPBStringEnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBStringEnumDictionary *dict2 = + [[GPBStringEnumDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBStringEnumDictionary *dict3 = + [[GPBStringEnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBStringEnumDictionary *dict4 = + [[GPBStringEnumDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBStringEnumDictionary *dict = + [[GPBStringEnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringEnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBStringEnumDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBStringEnumDictionary *dict = + [[GPBStringEnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringEnumDictionary *dict2 = + [GPBStringEnumDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBStringEnumDictionary *dict = [GPBStringEnumDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:700 forKey:@"foo"]; + XCTAssertEqual(dict.count, 1U); + + const NSString *kKeys[] = { @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 701, 702, 703 }; + GPBStringEnumDictionary *dict2 = + [[GPBStringEnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 703); + [dict2 release]; +} + +- (void)testRemove { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBStringEnumDictionary *dict = + [[GPBStringEnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 703); + + // Remove again does nothing. + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 703); + + [dict removeValueForKey:@"mumble"]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertFalse([dict valueForKey:@"baz" value:NULL]); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBStringEnumDictionary *dict = + [[GPBStringEnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 703); + + [dict setValue:703 forKey:@"foo"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 703); + + [dict setValue:701 forKey:@"mumble"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 701); + + const NSString *kKeys2[] = { @"bar", @"baz" }; + const int32_t kValues2[] = { 702, 700 }; + GPBStringEnumDictionary *dict2 = + [[GPBStringEnumDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 701); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - String -> Enum (Unknown Enums) + +@interface GPBStringEnumDictionaryUnknownEnumTests : XCTestCase +@end + +@implementation GPBStringEnumDictionaryUnknownEnumTests + +- (void)testRawBasics { + const NSString *kKeys[] = { @"foo", @"bar", @"baz" }; + const int32_t kValues[] = { 700, 801, 702 }; + GPBStringEnumDictionary *dict = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue(dict.validationFunc == TestingEnum_IsValidValue); // Pointer comparison + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" rawValue:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:@"baz" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" rawValue:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:@"mumble" rawValue:NULL]); + + __block NSUInteger idx = 0; + NSString **seenKeys = malloc(3 * sizeof(NSString*)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if ([kKeys[i] isEqual:seenKeys[j]]) { + foundKey = YES; + if (i == 1) { + XCTAssertEqual(kGPBUnrecognizedEnumeratorValue, seenValues[j], @"i = %d, j = %d", i, j); + } else { + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + idx = 0; + [dict enumerateKeysAndRawValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if ([kKeys[i] isEqual:seenKeys[j]]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndRawValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEqualityWithUnknowns { + const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" }; + const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" }; + const int32_t kValues1[] = { 700, 801, 702 }; // Unknown + const int32_t kValues2[] = { 700, 803, 702 }; // Unknown + const int32_t kValues3[] = { 700, 801, 702, 803 }; // Unknowns + GPBStringEnumDictionary *dict1 = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBStringEnumDictionary *dict1prime = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBStringEnumDictionary *dict2 = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBStringEnumDictionary *dict3 = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBStringEnumDictionary *dict4 = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopyWithUnknowns { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknown + GPBStringEnumDictionary *dict = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringEnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + XCTAssertEqualObjects(dict, dict2); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBStringEnumDictionary *dict = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringEnumDictionary *dict2 = + [GPBStringEnumDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + [dict release]; +} + +- (void)testUnknownAdds { + GPBStringEnumDictionary *dict = + [GPBStringEnumDictionary dictionaryWithValidationFunction:TestingEnum_IsValidValue]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + XCTAssertThrowsSpecificNamed([dict setValue:801 forKey:@"bar"], // Unknown + NSException, NSInvalidArgumentException); + XCTAssertEqual(dict.count, 0U); + [dict setRawValue:801 forKey:@"bar"]; // Unknown + XCTAssertEqual(dict.count, 1U); + + const NSString *kKeys[] = { @"foo", @"baz", @"mumble" }; + const int32_t kValues[] = { 700, 702, 803 }; // Unknown + GPBStringEnumDictionary *dict2 = + [[GPBStringEnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:&value]); + XCTAssertEqual(value, 803); + [dict2 release]; +} + +- (void)testUnknownRemove { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBStringEnumDictionary *dict = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:&value]); + XCTAssertEqual(value, 803); + + // Remove again does nothing. + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict removeValueForKey:@"mumble"]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertFalse([dict valueForKey:@"baz" value:NULL]); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + [dict release]; +} + +- (void)testInplaceMutationUnknowns { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBStringEnumDictionary *dict = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:&value]); + XCTAssertEqual(value, 803); + + XCTAssertThrowsSpecificNamed([dict setValue:803 forKey:@"foo"], // Unknown + NSException, NSInvalidArgumentException); + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict setRawValue:803 forKey:@"foo"]; // Unknown + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict setRawValue:700 forKey:@"mumble"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 700); + + const NSString *kKeys2[] = { @"bar", @"baz" }; + const int32_t kValues2[] = { 702, 801 }; // Unknown + GPBStringEnumDictionary *dict2 = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"baz" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 700); + + [dict2 release]; + [dict release]; +} + +- (void)testCopyUnknowns { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 700, 801, 702, 803 }; + GPBStringEnumDictionary *dict = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringEnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + XCTAssertTrue([dict2 isKindOfClass:[GPBStringEnumDictionary class]]); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND-END TESTS_FOR_POD_VALUES(String, NSString, *, Objects, @"foo", @"bar", @"baz", @"mumble") + diff --git a/objectivec/Tests/GPBDictionaryTests+UInt32.m b/objectivec/Tests/GPBDictionaryTests+UInt32.m new file mode 100644 index 00000000..a89ded3d --- /dev/null +++ b/objectivec/Tests/GPBDictionaryTests+UInt32.m @@ -0,0 +1,3650 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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. + +#import <Foundation/Foundation.h> +#import <XCTest/XCTest.h> + +#import "GPBDictionary.h" + +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h" + +// Pull in the macros (using an external file because expanding all tests +// in a single file makes a file that is failing to work with within Xcode. +//%PDDM-IMPORT-DEFINES GPBDictionaryTests.pddm + +//%PDDM-EXPAND TEST_FOR_POD_KEY(UInt32, uint32_t, 1U, 2U, 3U, 4U) +// This block of code is generated, do not edit it directly. + +#ifndef GPBARRAYSIZE +#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0])))) +#endif // GPBARRAYSIZE + +// To let the testing macros work, add some extra methods to simplify things. +@interface GPBUInt32EnumDictionary (TestingTweak) ++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(uint32_t)key; +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count; +@end + +static BOOL TestingEnum_IsValidValue(int32_t value) { + switch (value) { + case 700: + case 701: + case 702: + case 703: + return YES; + default: + return NO; + } +} + +@implementation GPBUInt32EnumDictionary (TestingTweak) ++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(uint32_t)key { + // Cast is needed to compiler knows what class we are invoking initWithValues: on to get the + // type correct. + return [[(GPBUInt32EnumDictionary*)[self alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:&value + forKeys:&key + count:1] autorelease]; +} +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count { + return [self initWithValidationFunction:TestingEnum_IsValidValue + rawValues:values + forKeys:keys + count:count]; +} +@end + + +#pragma mark - UInt32 -> UInt32 + +@interface GPBUInt32UInt32DictionaryTests : XCTestCase +@end + +@implementation GPBUInt32UInt32DictionaryTests + +- (void)testEmpty { + GPBUInt32UInt32Dictionary *dict = [[GPBUInt32UInt32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt32UInt32Dictionary *dict = [GPBUInt32UInt32Dictionary dictionaryWithValue:100U forKey:1U]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 1U); + XCTAssertEqual(aValue, 100U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint32_t kKeys[] = { 1U, 2U, 3U }; + const uint32_t kValues[] = { 100U, 101U, 102U }; + GPBUInt32UInt32Dictionary *dict = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + uint32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + __block NSUInteger idx = 0; + uint32_t *seenKeys = malloc(3 * sizeof(uint32_t)); + uint32_t *seenValues = malloc(3 * sizeof(uint32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U }; + const uint32_t kKeys2[] = { 2U, 1U, 4U }; + const uint32_t kValues1[] = { 100U, 101U, 102U }; + const uint32_t kValues2[] = { 100U, 103U, 102U }; + const uint32_t kValues3[] = { 100U, 101U, 102U, 103U }; + GPBUInt32UInt32Dictionary *dict1 = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt32UInt32Dictionary *dict1prime = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt32UInt32Dictionary *dict2 = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt32UInt32Dictionary *dict3 = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt32UInt32Dictionary *dict4 = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBUInt32UInt32Dictionary *dict = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32UInt32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32UInt32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBUInt32UInt32Dictionary *dict = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32UInt32Dictionary *dict2 = + [GPBUInt32UInt32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt32UInt32Dictionary *dict = [GPBUInt32UInt32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:100U forKey:1U]; + XCTAssertEqual(dict.count, 1U); + + const uint32_t kKeys[] = { 2U, 3U, 4U }; + const uint32_t kValues[] = { 101U, 102U, 103U }; + GPBUInt32UInt32Dictionary *dict2 = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + uint32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 103U); + [dict2 release]; +} + +- (void)testRemove { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBUInt32UInt32Dictionary *dict = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + uint32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 103U); + + // Remove again does nothing. + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 103U); + + [dict removeValueForKey:4U]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertFalse([dict valueForKey:3U value:NULL]); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBUInt32UInt32Dictionary *dict = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + uint32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 103U); + + [dict setValue:103U forKey:1U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 103U); + + [dict setValue:101U forKey:4U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 101U); + + const uint32_t kKeys2[] = { 2U, 3U }; + const uint32_t kValues2[] = { 102U, 100U }; + GPBUInt32UInt32Dictionary *dict2 = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 101U); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt32 -> Int32 + +@interface GPBUInt32Int32DictionaryTests : XCTestCase +@end + +@implementation GPBUInt32Int32DictionaryTests + +- (void)testEmpty { + GPBUInt32Int32Dictionary *dict = [[GPBUInt32Int32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt32Int32Dictionary *dict = [GPBUInt32Int32Dictionary dictionaryWithValue:200 forKey:1U]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 1U); + XCTAssertEqual(aValue, 200); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint32_t kKeys[] = { 1U, 2U, 3U }; + const int32_t kValues[] = { 200, 201, 202 }; + GPBUInt32Int32Dictionary *dict = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 202); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + __block NSUInteger idx = 0; + uint32_t *seenKeys = malloc(3 * sizeof(uint32_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U }; + const uint32_t kKeys2[] = { 2U, 1U, 4U }; + const int32_t kValues1[] = { 200, 201, 202 }; + const int32_t kValues2[] = { 200, 203, 202 }; + const int32_t kValues3[] = { 200, 201, 202, 203 }; + GPBUInt32Int32Dictionary *dict1 = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt32Int32Dictionary *dict1prime = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt32Int32Dictionary *dict2 = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt32Int32Dictionary *dict3 = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt32Int32Dictionary *dict4 = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBUInt32Int32Dictionary *dict = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32Int32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32Int32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBUInt32Int32Dictionary *dict = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32Int32Dictionary *dict2 = + [GPBUInt32Int32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt32Int32Dictionary *dict = [GPBUInt32Int32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:200 forKey:1U]; + XCTAssertEqual(dict.count, 1U); + + const uint32_t kKeys[] = { 2U, 3U, 4U }; + const int32_t kValues[] = { 201, 202, 203 }; + GPBUInt32Int32Dictionary *dict2 = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 203); + [dict2 release]; +} + +- (void)testRemove { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBUInt32Int32Dictionary *dict = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 203); + + // Remove again does nothing. + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 203); + + [dict removeValueForKey:4U]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 202); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertFalse([dict valueForKey:3U value:NULL]); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBUInt32Int32Dictionary *dict = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 203); + + [dict setValue:203 forKey:1U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 203); + + [dict setValue:201 forKey:4U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 201); + + const uint32_t kKeys2[] = { 2U, 3U }; + const int32_t kValues2[] = { 202, 200 }; + GPBUInt32Int32Dictionary *dict2 = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 201); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt32 -> UInt64 + +@interface GPBUInt32UInt64DictionaryTests : XCTestCase +@end + +@implementation GPBUInt32UInt64DictionaryTests + +- (void)testEmpty { + GPBUInt32UInt64Dictionary *dict = [[GPBUInt32UInt64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt32UInt64Dictionary *dict = [GPBUInt32UInt64Dictionary dictionaryWithValue:300U forKey:1U]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint64_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint64_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 1U); + XCTAssertEqual(aValue, 300U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint32_t kKeys[] = { 1U, 2U, 3U }; + const uint64_t kValues[] = { 300U, 301U, 302U }; + GPBUInt32UInt64Dictionary *dict = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + uint64_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + __block NSUInteger idx = 0; + uint32_t *seenKeys = malloc(3 * sizeof(uint32_t)); + uint64_t *seenValues = malloc(3 * sizeof(uint64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U }; + const uint32_t kKeys2[] = { 2U, 1U, 4U }; + const uint64_t kValues1[] = { 300U, 301U, 302U }; + const uint64_t kValues2[] = { 300U, 303U, 302U }; + const uint64_t kValues3[] = { 300U, 301U, 302U, 303U }; + GPBUInt32UInt64Dictionary *dict1 = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt32UInt64Dictionary *dict1prime = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt32UInt64Dictionary *dict2 = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt32UInt64Dictionary *dict3 = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt32UInt64Dictionary *dict4 = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBUInt32UInt64Dictionary *dict = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32UInt64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32UInt64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBUInt32UInt64Dictionary *dict = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32UInt64Dictionary *dict2 = + [GPBUInt32UInt64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt32UInt64Dictionary *dict = [GPBUInt32UInt64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:300U forKey:1U]; + XCTAssertEqual(dict.count, 1U); + + const uint32_t kKeys[] = { 2U, 3U, 4U }; + const uint64_t kValues[] = { 301U, 302U, 303U }; + GPBUInt32UInt64Dictionary *dict2 = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + uint64_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 303U); + [dict2 release]; +} + +- (void)testRemove { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBUInt32UInt64Dictionary *dict = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + uint64_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 303U); + + // Remove again does nothing. + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 303U); + + [dict removeValueForKey:4U]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertFalse([dict valueForKey:3U value:NULL]); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBUInt32UInt64Dictionary *dict = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + uint64_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 303U); + + [dict setValue:303U forKey:1U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 303U); + + [dict setValue:301U forKey:4U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 301U); + + const uint32_t kKeys2[] = { 2U, 3U }; + const uint64_t kValues2[] = { 302U, 300U }; + GPBUInt32UInt64Dictionary *dict2 = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 301U); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt32 -> Int64 + +@interface GPBUInt32Int64DictionaryTests : XCTestCase +@end + +@implementation GPBUInt32Int64DictionaryTests + +- (void)testEmpty { + GPBUInt32Int64Dictionary *dict = [[GPBUInt32Int64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt32Int64Dictionary *dict = [GPBUInt32Int64Dictionary dictionaryWithValue:400 forKey:1U]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int64_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int64_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 1U); + XCTAssertEqual(aValue, 400); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint32_t kKeys[] = { 1U, 2U, 3U }; + const int64_t kValues[] = { 400, 401, 402 }; + GPBUInt32Int64Dictionary *dict = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int64_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 402); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + __block NSUInteger idx = 0; + uint32_t *seenKeys = malloc(3 * sizeof(uint32_t)); + int64_t *seenValues = malloc(3 * sizeof(int64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U }; + const uint32_t kKeys2[] = { 2U, 1U, 4U }; + const int64_t kValues1[] = { 400, 401, 402 }; + const int64_t kValues2[] = { 400, 403, 402 }; + const int64_t kValues3[] = { 400, 401, 402, 403 }; + GPBUInt32Int64Dictionary *dict1 = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt32Int64Dictionary *dict1prime = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt32Int64Dictionary *dict2 = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt32Int64Dictionary *dict3 = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt32Int64Dictionary *dict4 = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBUInt32Int64Dictionary *dict = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32Int64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32Int64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBUInt32Int64Dictionary *dict = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32Int64Dictionary *dict2 = + [GPBUInt32Int64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt32Int64Dictionary *dict = [GPBUInt32Int64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:400 forKey:1U]; + XCTAssertEqual(dict.count, 1U); + + const uint32_t kKeys[] = { 2U, 3U, 4U }; + const int64_t kValues[] = { 401, 402, 403 }; + GPBUInt32Int64Dictionary *dict2 = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int64_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 403); + [dict2 release]; +} + +- (void)testRemove { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBUInt32Int64Dictionary *dict = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + int64_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 403); + + // Remove again does nothing. + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 403); + + [dict removeValueForKey:4U]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 402); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertFalse([dict valueForKey:3U value:NULL]); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBUInt32Int64Dictionary *dict = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int64_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 403); + + [dict setValue:403 forKey:1U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 403); + + [dict setValue:401 forKey:4U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 401); + + const uint32_t kKeys2[] = { 2U, 3U }; + const int64_t kValues2[] = { 402, 400 }; + GPBUInt32Int64Dictionary *dict2 = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 401); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt32 -> Bool + +@interface GPBUInt32BoolDictionaryTests : XCTestCase +@end + +@implementation GPBUInt32BoolDictionaryTests + +- (void)testEmpty { + GPBUInt32BoolDictionary *dict = [[GPBUInt32BoolDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt32BoolDictionary *dict = [GPBUInt32BoolDictionary dictionaryWithValue:YES forKey:1U]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + BOOL value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, BOOL aValue, BOOL *stop) { + XCTAssertEqual(aKey, 1U); + XCTAssertEqual(aValue, YES); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint32_t kKeys[] = { 1U, 2U, 3U }; + const BOOL kValues[] = { YES, YES, NO }; + GPBUInt32BoolDictionary *dict = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + BOOL value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + __block NSUInteger idx = 0; + uint32_t *seenKeys = malloc(3 * sizeof(uint32_t)); + BOOL *seenValues = malloc(3 * sizeof(BOOL)); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, BOOL aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U }; + const uint32_t kKeys2[] = { 2U, 1U, 4U }; + const BOOL kValues1[] = { YES, YES, NO }; + const BOOL kValues2[] = { YES, NO, NO }; + const BOOL kValues3[] = { YES, YES, NO, NO }; + GPBUInt32BoolDictionary *dict1 = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt32BoolDictionary *dict1prime = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt32BoolDictionary *dict2 = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt32BoolDictionary *dict3 = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt32BoolDictionary *dict4 = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBUInt32BoolDictionary *dict = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32BoolDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32BoolDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBUInt32BoolDictionary *dict = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32BoolDictionary *dict2 = + [GPBUInt32BoolDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt32BoolDictionary *dict = [GPBUInt32BoolDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:YES forKey:1U]; + XCTAssertEqual(dict.count, 1U); + + const uint32_t kKeys[] = { 2U, 3U, 4U }; + const BOOL kValues[] = { YES, NO, NO }; + GPBUInt32BoolDictionary *dict2 = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + BOOL value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, NO); + [dict2 release]; +} + +- (void)testRemove { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBUInt32BoolDictionary *dict = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + BOOL value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, NO); + + // Remove again does nothing. + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, NO); + + [dict removeValueForKey:4U]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertFalse([dict valueForKey:3U value:NULL]); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBUInt32BoolDictionary *dict = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + BOOL value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, NO); + + [dict setValue:NO forKey:1U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, NO); + + [dict setValue:YES forKey:4U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, YES); + + const uint32_t kKeys2[] = { 2U, 3U }; + const BOOL kValues2[] = { NO, YES }; + GPBUInt32BoolDictionary *dict2 = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, YES); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt32 -> Float + +@interface GPBUInt32FloatDictionaryTests : XCTestCase +@end + +@implementation GPBUInt32FloatDictionaryTests + +- (void)testEmpty { + GPBUInt32FloatDictionary *dict = [[GPBUInt32FloatDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt32FloatDictionary *dict = [GPBUInt32FloatDictionary dictionaryWithValue:500.f forKey:1U]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + float value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, float aValue, BOOL *stop) { + XCTAssertEqual(aKey, 1U); + XCTAssertEqual(aValue, 500.f); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint32_t kKeys[] = { 1U, 2U, 3U }; + const float kValues[] = { 500.f, 501.f, 502.f }; + GPBUInt32FloatDictionary *dict = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + float value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + __block NSUInteger idx = 0; + uint32_t *seenKeys = malloc(3 * sizeof(uint32_t)); + float *seenValues = malloc(3 * sizeof(float)); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, float aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U }; + const uint32_t kKeys2[] = { 2U, 1U, 4U }; + const float kValues1[] = { 500.f, 501.f, 502.f }; + const float kValues2[] = { 500.f, 503.f, 502.f }; + const float kValues3[] = { 500.f, 501.f, 502.f, 503.f }; + GPBUInt32FloatDictionary *dict1 = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt32FloatDictionary *dict1prime = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt32FloatDictionary *dict2 = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt32FloatDictionary *dict3 = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt32FloatDictionary *dict4 = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBUInt32FloatDictionary *dict = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32FloatDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32FloatDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBUInt32FloatDictionary *dict = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32FloatDictionary *dict2 = + [GPBUInt32FloatDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt32FloatDictionary *dict = [GPBUInt32FloatDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:500.f forKey:1U]; + XCTAssertEqual(dict.count, 1U); + + const uint32_t kKeys[] = { 2U, 3U, 4U }; + const float kValues[] = { 501.f, 502.f, 503.f }; + GPBUInt32FloatDictionary *dict2 = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + float value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 503.f); + [dict2 release]; +} + +- (void)testRemove { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBUInt32FloatDictionary *dict = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + float value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 503.f); + + // Remove again does nothing. + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 503.f); + + [dict removeValueForKey:4U]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertFalse([dict valueForKey:3U value:NULL]); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBUInt32FloatDictionary *dict = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + float value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 503.f); + + [dict setValue:503.f forKey:1U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 503.f); + + [dict setValue:501.f forKey:4U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 501.f); + + const uint32_t kKeys2[] = { 2U, 3U }; + const float kValues2[] = { 502.f, 500.f }; + GPBUInt32FloatDictionary *dict2 = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 501.f); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt32 -> Double + +@interface GPBUInt32DoubleDictionaryTests : XCTestCase +@end + +@implementation GPBUInt32DoubleDictionaryTests + +- (void)testEmpty { + GPBUInt32DoubleDictionary *dict = [[GPBUInt32DoubleDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt32DoubleDictionary *dict = [GPBUInt32DoubleDictionary dictionaryWithValue:600. forKey:1U]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + double value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, double aValue, BOOL *stop) { + XCTAssertEqual(aKey, 1U); + XCTAssertEqual(aValue, 600.); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint32_t kKeys[] = { 1U, 2U, 3U }; + const double kValues[] = { 600., 601., 602. }; + GPBUInt32DoubleDictionary *dict = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + double value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + __block NSUInteger idx = 0; + uint32_t *seenKeys = malloc(3 * sizeof(uint32_t)); + double *seenValues = malloc(3 * sizeof(double)); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, double aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U }; + const uint32_t kKeys2[] = { 2U, 1U, 4U }; + const double kValues1[] = { 600., 601., 602. }; + const double kValues2[] = { 600., 603., 602. }; + const double kValues3[] = { 600., 601., 602., 603. }; + GPBUInt32DoubleDictionary *dict1 = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt32DoubleDictionary *dict1prime = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt32DoubleDictionary *dict2 = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt32DoubleDictionary *dict3 = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt32DoubleDictionary *dict4 = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBUInt32DoubleDictionary *dict = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32DoubleDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32DoubleDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBUInt32DoubleDictionary *dict = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32DoubleDictionary *dict2 = + [GPBUInt32DoubleDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt32DoubleDictionary *dict = [GPBUInt32DoubleDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:600. forKey:1U]; + XCTAssertEqual(dict.count, 1U); + + const uint32_t kKeys[] = { 2U, 3U, 4U }; + const double kValues[] = { 601., 602., 603. }; + GPBUInt32DoubleDictionary *dict2 = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + double value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 603.); + [dict2 release]; +} + +- (void)testRemove { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBUInt32DoubleDictionary *dict = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + double value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 603.); + + // Remove again does nothing. + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 603.); + + [dict removeValueForKey:4U]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertFalse([dict valueForKey:3U value:NULL]); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBUInt32DoubleDictionary *dict = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + double value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 603.); + + [dict setValue:603. forKey:1U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 603.); + + [dict setValue:601. forKey:4U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 601.); + + const uint32_t kKeys2[] = { 2U, 3U }; + const double kValues2[] = { 602., 600. }; + GPBUInt32DoubleDictionary *dict2 = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 601.); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt32 -> Enum + +@interface GPBUInt32EnumDictionaryTests : XCTestCase +@end + +@implementation GPBUInt32EnumDictionaryTests + +- (void)testEmpty { + GPBUInt32EnumDictionary *dict = [[GPBUInt32EnumDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt32EnumDictionary *dict = [GPBUInt32EnumDictionary dictionaryWithValue:700 forKey:1U]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 1U); + XCTAssertEqual(aValue, 700); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint32_t kKeys[] = { 1U, 2U, 3U }; + const int32_t kValues[] = { 700, 701, 702 }; + GPBUInt32EnumDictionary *dict = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + __block NSUInteger idx = 0; + uint32_t *seenKeys = malloc(3 * sizeof(uint32_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U }; + const uint32_t kKeys2[] = { 2U, 1U, 4U }; + const int32_t kValues1[] = { 700, 701, 702 }; + const int32_t kValues2[] = { 700, 703, 702 }; + const int32_t kValues3[] = { 700, 701, 702, 703 }; + GPBUInt32EnumDictionary *dict1 = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt32EnumDictionary *dict1prime = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt32EnumDictionary *dict2 = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt32EnumDictionary *dict3 = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt32EnumDictionary *dict4 = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBUInt32EnumDictionary *dict = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32EnumDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBUInt32EnumDictionary *dict = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32EnumDictionary *dict2 = + [GPBUInt32EnumDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt32EnumDictionary *dict = [GPBUInt32EnumDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:700 forKey:1U]; + XCTAssertEqual(dict.count, 1U); + + const uint32_t kKeys[] = { 2U, 3U, 4U }; + const int32_t kValues[] = { 701, 702, 703 }; + GPBUInt32EnumDictionary *dict2 = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 703); + [dict2 release]; +} + +- (void)testRemove { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBUInt32EnumDictionary *dict = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 703); + + // Remove again does nothing. + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 703); + + [dict removeValueForKey:4U]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertFalse([dict valueForKey:3U value:NULL]); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBUInt32EnumDictionary *dict = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 703); + + [dict setValue:703 forKey:1U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 703); + + [dict setValue:701 forKey:4U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 701); + + const uint32_t kKeys2[] = { 2U, 3U }; + const int32_t kValues2[] = { 702, 700 }; + GPBUInt32EnumDictionary *dict2 = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 701); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt32 -> Enum (Unknown Enums) + +@interface GPBUInt32EnumDictionaryUnknownEnumTests : XCTestCase +@end + +@implementation GPBUInt32EnumDictionaryUnknownEnumTests + +- (void)testRawBasics { + const uint32_t kKeys[] = { 1U, 2U, 3U }; + const int32_t kValues[] = { 700, 801, 702 }; + GPBUInt32EnumDictionary *dict = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue(dict.validationFunc == TestingEnum_IsValidValue); // Pointer comparison + int32_t value; + XCTAssertTrue([dict valueForKey:1U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:1U rawValue:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:2U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:2U rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:3U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:3U rawValue:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:4U rawValue:NULL]); + + __block NSUInteger idx = 0; + uint32_t *seenKeys = malloc(3 * sizeof(uint32_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + if (i == 1) { + XCTAssertEqual(kGPBUnrecognizedEnumeratorValue, seenValues[j], @"i = %d, j = %d", i, j); + } else { + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + idx = 0; + [dict enumerateKeysAndRawValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndRawValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEqualityWithUnknowns { + const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U }; + const uint32_t kKeys2[] = { 2U, 1U, 4U }; + const int32_t kValues1[] = { 700, 801, 702 }; // Unknown + const int32_t kValues2[] = { 700, 803, 702 }; // Unknown + const int32_t kValues3[] = { 700, 801, 702, 803 }; // Unknowns + GPBUInt32EnumDictionary *dict1 = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt32EnumDictionary *dict1prime = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt32EnumDictionary *dict2 = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt32EnumDictionary *dict3 = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt32EnumDictionary *dict4 = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopyWithUnknowns { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknown + GPBUInt32EnumDictionary *dict = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + XCTAssertEqualObjects(dict, dict2); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBUInt32EnumDictionary *dict = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32EnumDictionary *dict2 = + [GPBUInt32EnumDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + [dict release]; +} + +- (void)testUnknownAdds { + GPBUInt32EnumDictionary *dict = + [GPBUInt32EnumDictionary dictionaryWithValidationFunction:TestingEnum_IsValidValue]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + XCTAssertThrowsSpecificNamed([dict setValue:801 forKey:2U], // Unknown + NSException, NSInvalidArgumentException); + XCTAssertEqual(dict.count, 0U); + [dict setRawValue:801 forKey:2U]; // Unknown + XCTAssertEqual(dict.count, 1U); + + const uint32_t kKeys[] = { 1U, 3U, 4U }; + const int32_t kValues[] = { 700, 702, 803 }; // Unknown + GPBUInt32EnumDictionary *dict2 = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:2U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:2U rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:4U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:4U rawValue:&value]); + XCTAssertEqual(value, 803); + [dict2 release]; +} + +- (void)testUnknownRemove { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBUInt32EnumDictionary *dict = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:4U rawValue:&value]); + XCTAssertEqual(value, 803); + + // Remove again does nothing. + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:4U rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict removeValueForKey:4U]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertFalse([dict valueForKey:3U value:NULL]); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + [dict release]; +} + +- (void)testInplaceMutationUnknowns { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBUInt32EnumDictionary *dict = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:2U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:2U rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:4U rawValue:&value]); + XCTAssertEqual(value, 803); + + XCTAssertThrowsSpecificNamed([dict setValue:803 forKey:1U], // Unknown + NSException, NSInvalidArgumentException); + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:2U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:2U rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:4U rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict setRawValue:803 forKey:1U]; // Unknown + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:1U rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:2U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:2U rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:4U rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict setRawValue:700 forKey:4U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:1U rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:2U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:2U rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 700); + + const uint32_t kKeys2[] = { 2U, 3U }; + const int32_t kValues2[] = { 702, 801 }; // Unknown + GPBUInt32EnumDictionary *dict2 = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:1U rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:3U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:3U rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 700); + + [dict2 release]; + [dict release]; +} + +- (void)testCopyUnknowns { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 700, 801, 702, 803 }; + GPBUInt32EnumDictionary *dict = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32EnumDictionary class]]); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt32 -> Object + +@interface GPBUInt32ObjectDictionaryTests : XCTestCase +@end + +@implementation GPBUInt32ObjectDictionaryTests + +- (void)testEmpty { + GPBUInt32ObjectDictionary *dict = [[GPBUInt32ObjectDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertNil([dict valueForKey:1U]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, id aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt32ObjectDictionary *dict = [GPBUInt32ObjectDictionary dictionaryWithValue:@"abc" forKey:1U]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + XCTAssertEqualObjects([dict valueForKey:1U], @"abc"); + XCTAssertNil([dict valueForKey:2U]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, id aValue, BOOL *stop) { + XCTAssertEqual(aKey, 1U); + XCTAssertEqualObjects(aValue, @"abc"); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint32_t kKeys[] = { 1U, 2U, 3U }; + const id kValues[] = { @"abc", @"def", @"ghi" }; + GPBUInt32ObjectDictionary *dict = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:1U], @"abc"); + XCTAssertEqualObjects([dict valueForKey:2U], @"def"); + XCTAssertEqualObjects([dict valueForKey:3U], @"ghi"); + XCTAssertNil([dict valueForKey:4U]); + + __block NSUInteger idx = 0; + uint32_t *seenKeys = malloc(3 * sizeof(uint32_t)); + id *seenValues = malloc(3 * sizeof(id)); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, id aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqualObjects(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, id aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U }; + const uint32_t kKeys2[] = { 2U, 1U, 4U }; + const id kValues1[] = { @"abc", @"def", @"ghi" }; + const id kValues2[] = { @"abc", @"jkl", @"ghi" }; + const id kValues3[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBUInt32ObjectDictionary *dict1 = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt32ObjectDictionary *dict1prime = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt32ObjectDictionary *dict2 = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt32ObjectDictionary *dict3 = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt32ObjectDictionary *dict4 = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBUInt32ObjectDictionary *dict = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32ObjectDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32ObjectDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBUInt32ObjectDictionary *dict = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32ObjectDictionary *dict2 = + [GPBUInt32ObjectDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt32ObjectDictionary *dict = [GPBUInt32ObjectDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:@"abc" forKey:1U]; + XCTAssertEqual(dict.count, 1U); + + const uint32_t kKeys[] = { 2U, 3U, 4U }; + const id kValues[] = { @"def", @"ghi", @"jkl" }; + GPBUInt32ObjectDictionary *dict2 = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + XCTAssertEqualObjects([dict valueForKey:1U], @"abc"); + XCTAssertEqualObjects([dict valueForKey:2U], @"def"); + XCTAssertEqualObjects([dict valueForKey:3U], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:4U], @"jkl"); + [dict2 release]; +} + +- (void)testRemove { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBUInt32ObjectDictionary *dict = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:1U], @"abc"); + XCTAssertNil([dict valueForKey:2U]); + XCTAssertEqualObjects([dict valueForKey:3U], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:4U], @"jkl"); + + // Remove again does nothing. + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:1U], @"abc"); + XCTAssertNil([dict valueForKey:2U]); + XCTAssertEqualObjects([dict valueForKey:3U], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:4U], @"jkl"); + + [dict removeValueForKey:4U]; + XCTAssertEqual(dict.count, 2U); + XCTAssertEqualObjects([dict valueForKey:1U], @"abc"); + XCTAssertNil([dict valueForKey:2U]); + XCTAssertEqualObjects([dict valueForKey:3U], @"ghi"); + XCTAssertNil([dict valueForKey:4U]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertNil([dict valueForKey:1U]); + XCTAssertNil([dict valueForKey:2U]); + XCTAssertNil([dict valueForKey:3U]); + XCTAssertNil([dict valueForKey:4U]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBUInt32ObjectDictionary *dict = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:1U], @"abc"); + XCTAssertEqualObjects([dict valueForKey:2U], @"def"); + XCTAssertEqualObjects([dict valueForKey:3U], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:4U], @"jkl"); + + [dict setValue:@"jkl" forKey:1U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:1U], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:2U], @"def"); + XCTAssertEqualObjects([dict valueForKey:3U], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:4U], @"jkl"); + + [dict setValue:@"def" forKey:4U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:1U], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:2U], @"def"); + XCTAssertEqualObjects([dict valueForKey:3U], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:4U], @"def"); + + const uint32_t kKeys2[] = { 2U, 3U }; + const id kValues2[] = { @"ghi", @"abc" }; + GPBUInt32ObjectDictionary *dict2 = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:1U], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:2U], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:3U], @"abc"); + XCTAssertEqualObjects([dict valueForKey:4U], @"def"); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND-END TEST_FOR_POD_KEY(UInt32, uint32_t, 1U, 2U, 3U, 4U) + diff --git a/objectivec/Tests/GPBDictionaryTests+UInt64.m b/objectivec/Tests/GPBDictionaryTests+UInt64.m new file mode 100644 index 00000000..355639c6 --- /dev/null +++ b/objectivec/Tests/GPBDictionaryTests+UInt64.m @@ -0,0 +1,3649 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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. + +#import <Foundation/Foundation.h> +#import <XCTest/XCTest.h> + +#import "GPBDictionary.h" + +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h" + +// Pull in the macros (using an external file because expanding all tests +// in a single file makes a file that is failing to work with within Xcode. +//%PDDM-IMPORT-DEFINES GPBDictionaryTests.pddm + +//%PDDM-EXPAND TEST_FOR_POD_KEY(UInt64, uint64_t, 31ULL, 32ULL, 33ULL, 34ULL) +// This block of code is generated, do not edit it directly. + +#ifndef GPBARRAYSIZE +#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0])))) +#endif // GPBARRAYSIZE + +// To let the testing macros work, add some extra methods to simplify things. +@interface GPBUInt64EnumDictionary (TestingTweak) ++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(uint64_t)key; +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count; +@end + +static BOOL TestingEnum_IsValidValue(int32_t value) { + switch (value) { + case 700: + case 701: + case 702: + case 703: + return YES; + default: + return NO; + } +} + +@implementation GPBUInt64EnumDictionary (TestingTweak) ++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(uint64_t)key { + // Cast is needed to compiler knows what class we are invoking initWithValues: on to get the + // type correct. + return [[(GPBUInt64EnumDictionary*)[self alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:&value + forKeys:&key + count:1] autorelease]; +} +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count { + return [self initWithValidationFunction:TestingEnum_IsValidValue + rawValues:values + forKeys:keys + count:count]; +} +@end + + +#pragma mark - UInt64 -> UInt32 + +@interface GPBUInt64UInt32DictionaryTests : XCTestCase +@end + +@implementation GPBUInt64UInt32DictionaryTests + +- (void)testEmpty { + GPBUInt64UInt32Dictionary *dict = [[GPBUInt64UInt32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt64UInt32Dictionary *dict = [GPBUInt64UInt32Dictionary dictionaryWithValue:100U forKey:31ULL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 31ULL); + XCTAssertEqual(aValue, 100U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL }; + const uint32_t kValues[] = { 100U, 101U, 102U }; + GPBUInt64UInt32Dictionary *dict = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + uint32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + __block NSUInteger idx = 0; + uint64_t *seenKeys = malloc(3 * sizeof(uint64_t)); + uint32_t *seenValues = malloc(3 * sizeof(uint32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL }; + const uint32_t kValues1[] = { 100U, 101U, 102U }; + const uint32_t kValues2[] = { 100U, 103U, 102U }; + const uint32_t kValues3[] = { 100U, 101U, 102U, 103U }; + GPBUInt64UInt32Dictionary *dict1 = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt64UInt32Dictionary *dict1prime = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt64UInt32Dictionary *dict2 = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt64UInt32Dictionary *dict3 = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt64UInt32Dictionary *dict4 = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBUInt64UInt32Dictionary *dict = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64UInt32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64UInt32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBUInt64UInt32Dictionary *dict = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64UInt32Dictionary *dict2 = + [GPBUInt64UInt32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt64UInt32Dictionary *dict = [GPBUInt64UInt32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:100U forKey:31ULL]; + XCTAssertEqual(dict.count, 1U); + + const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL }; + const uint32_t kValues[] = { 101U, 102U, 103U }; + GPBUInt64UInt32Dictionary *dict2 = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + uint32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 103U); + [dict2 release]; +} + +- (void)testRemove { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBUInt64UInt32Dictionary *dict = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + uint32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 103U); + + // Remove again does nothing. + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 103U); + + [dict removeValueForKey:34ULL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertFalse([dict valueForKey:33ULL value:NULL]); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBUInt64UInt32Dictionary *dict = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + uint32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 103U); + + [dict setValue:103U forKey:31ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 103U); + + [dict setValue:101U forKey:34ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 101U); + + const uint64_t kKeys2[] = { 32ULL, 33ULL }; + const uint32_t kValues2[] = { 102U, 100U }; + GPBUInt64UInt32Dictionary *dict2 = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 101U); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt64 -> Int32 + +@interface GPBUInt64Int32DictionaryTests : XCTestCase +@end + +@implementation GPBUInt64Int32DictionaryTests + +- (void)testEmpty { + GPBUInt64Int32Dictionary *dict = [[GPBUInt64Int32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt64Int32Dictionary *dict = [GPBUInt64Int32Dictionary dictionaryWithValue:200 forKey:31ULL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 31ULL); + XCTAssertEqual(aValue, 200); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL }; + const int32_t kValues[] = { 200, 201, 202 }; + GPBUInt64Int32Dictionary *dict = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + __block NSUInteger idx = 0; + uint64_t *seenKeys = malloc(3 * sizeof(uint64_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL }; + const int32_t kValues1[] = { 200, 201, 202 }; + const int32_t kValues2[] = { 200, 203, 202 }; + const int32_t kValues3[] = { 200, 201, 202, 203 }; + GPBUInt64Int32Dictionary *dict1 = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt64Int32Dictionary *dict1prime = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt64Int32Dictionary *dict2 = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt64Int32Dictionary *dict3 = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt64Int32Dictionary *dict4 = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBUInt64Int32Dictionary *dict = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64Int32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64Int32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBUInt64Int32Dictionary *dict = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64Int32Dictionary *dict2 = + [GPBUInt64Int32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt64Int32Dictionary *dict = [GPBUInt64Int32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:200 forKey:31ULL]; + XCTAssertEqual(dict.count, 1U); + + const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 201, 202, 203 }; + GPBUInt64Int32Dictionary *dict2 = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 203); + [dict2 release]; +} + +- (void)testRemove { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBUInt64Int32Dictionary *dict = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 203); + + // Remove again does nothing. + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 203); + + [dict removeValueForKey:34ULL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertFalse([dict valueForKey:33ULL value:NULL]); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBUInt64Int32Dictionary *dict = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 203); + + [dict setValue:203 forKey:31ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 203); + + [dict setValue:201 forKey:34ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 201); + + const uint64_t kKeys2[] = { 32ULL, 33ULL }; + const int32_t kValues2[] = { 202, 200 }; + GPBUInt64Int32Dictionary *dict2 = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 201); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt64 -> UInt64 + +@interface GPBUInt64UInt64DictionaryTests : XCTestCase +@end + +@implementation GPBUInt64UInt64DictionaryTests + +- (void)testEmpty { + GPBUInt64UInt64Dictionary *dict = [[GPBUInt64UInt64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt64UInt64Dictionary *dict = [GPBUInt64UInt64Dictionary dictionaryWithValue:300U forKey:31ULL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint64_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint64_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 31ULL); + XCTAssertEqual(aValue, 300U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL }; + const uint64_t kValues[] = { 300U, 301U, 302U }; + GPBUInt64UInt64Dictionary *dict = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + uint64_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + __block NSUInteger idx = 0; + uint64_t *seenKeys = malloc(3 * sizeof(uint64_t)); + uint64_t *seenValues = malloc(3 * sizeof(uint64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL }; + const uint64_t kValues1[] = { 300U, 301U, 302U }; + const uint64_t kValues2[] = { 300U, 303U, 302U }; + const uint64_t kValues3[] = { 300U, 301U, 302U, 303U }; + GPBUInt64UInt64Dictionary *dict1 = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt64UInt64Dictionary *dict1prime = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt64UInt64Dictionary *dict2 = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt64UInt64Dictionary *dict3 = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt64UInt64Dictionary *dict4 = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBUInt64UInt64Dictionary *dict = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64UInt64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64UInt64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBUInt64UInt64Dictionary *dict = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64UInt64Dictionary *dict2 = + [GPBUInt64UInt64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt64UInt64Dictionary *dict = [GPBUInt64UInt64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:300U forKey:31ULL]; + XCTAssertEqual(dict.count, 1U); + + const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL }; + const uint64_t kValues[] = { 301U, 302U, 303U }; + GPBUInt64UInt64Dictionary *dict2 = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + uint64_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 303U); + [dict2 release]; +} + +- (void)testRemove { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBUInt64UInt64Dictionary *dict = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + uint64_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 303U); + + // Remove again does nothing. + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 303U); + + [dict removeValueForKey:34ULL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertFalse([dict valueForKey:33ULL value:NULL]); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBUInt64UInt64Dictionary *dict = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + uint64_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 303U); + + [dict setValue:303U forKey:31ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 303U); + + [dict setValue:301U forKey:34ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 301U); + + const uint64_t kKeys2[] = { 32ULL, 33ULL }; + const uint64_t kValues2[] = { 302U, 300U }; + GPBUInt64UInt64Dictionary *dict2 = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 301U); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt64 -> Int64 + +@interface GPBUInt64Int64DictionaryTests : XCTestCase +@end + +@implementation GPBUInt64Int64DictionaryTests + +- (void)testEmpty { + GPBUInt64Int64Dictionary *dict = [[GPBUInt64Int64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt64Int64Dictionary *dict = [GPBUInt64Int64Dictionary dictionaryWithValue:400 forKey:31ULL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int64_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int64_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 31ULL); + XCTAssertEqual(aValue, 400); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL }; + const int64_t kValues[] = { 400, 401, 402 }; + GPBUInt64Int64Dictionary *dict = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int64_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + __block NSUInteger idx = 0; + uint64_t *seenKeys = malloc(3 * sizeof(uint64_t)); + int64_t *seenValues = malloc(3 * sizeof(int64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL }; + const int64_t kValues1[] = { 400, 401, 402 }; + const int64_t kValues2[] = { 400, 403, 402 }; + const int64_t kValues3[] = { 400, 401, 402, 403 }; + GPBUInt64Int64Dictionary *dict1 = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt64Int64Dictionary *dict1prime = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt64Int64Dictionary *dict2 = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt64Int64Dictionary *dict3 = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt64Int64Dictionary *dict4 = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBUInt64Int64Dictionary *dict = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64Int64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64Int64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBUInt64Int64Dictionary *dict = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64Int64Dictionary *dict2 = + [GPBUInt64Int64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt64Int64Dictionary *dict = [GPBUInt64Int64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:400 forKey:31ULL]; + XCTAssertEqual(dict.count, 1U); + + const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL }; + const int64_t kValues[] = { 401, 402, 403 }; + GPBUInt64Int64Dictionary *dict2 = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int64_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 403); + [dict2 release]; +} + +- (void)testRemove { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBUInt64Int64Dictionary *dict = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + int64_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 403); + + // Remove again does nothing. + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 403); + + [dict removeValueForKey:34ULL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertFalse([dict valueForKey:33ULL value:NULL]); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBUInt64Int64Dictionary *dict = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int64_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 403); + + [dict setValue:403 forKey:31ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 403); + + [dict setValue:401 forKey:34ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 401); + + const uint64_t kKeys2[] = { 32ULL, 33ULL }; + const int64_t kValues2[] = { 402, 400 }; + GPBUInt64Int64Dictionary *dict2 = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 401); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt64 -> Bool + +@interface GPBUInt64BoolDictionaryTests : XCTestCase +@end + +@implementation GPBUInt64BoolDictionaryTests + +- (void)testEmpty { + GPBUInt64BoolDictionary *dict = [[GPBUInt64BoolDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt64BoolDictionary *dict = [GPBUInt64BoolDictionary dictionaryWithValue:YES forKey:31ULL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + BOOL value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, BOOL aValue, BOOL *stop) { + XCTAssertEqual(aKey, 31ULL); + XCTAssertEqual(aValue, YES); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL }; + const BOOL kValues[] = { YES, YES, NO }; + GPBUInt64BoolDictionary *dict = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + BOOL value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + __block NSUInteger idx = 0; + uint64_t *seenKeys = malloc(3 * sizeof(uint64_t)); + BOOL *seenValues = malloc(3 * sizeof(BOOL)); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, BOOL aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL }; + const BOOL kValues1[] = { YES, YES, NO }; + const BOOL kValues2[] = { YES, NO, NO }; + const BOOL kValues3[] = { YES, YES, NO, NO }; + GPBUInt64BoolDictionary *dict1 = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt64BoolDictionary *dict1prime = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt64BoolDictionary *dict2 = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt64BoolDictionary *dict3 = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt64BoolDictionary *dict4 = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBUInt64BoolDictionary *dict = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64BoolDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64BoolDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBUInt64BoolDictionary *dict = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64BoolDictionary *dict2 = + [GPBUInt64BoolDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt64BoolDictionary *dict = [GPBUInt64BoolDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:YES forKey:31ULL]; + XCTAssertEqual(dict.count, 1U); + + const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL }; + const BOOL kValues[] = { YES, NO, NO }; + GPBUInt64BoolDictionary *dict2 = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + BOOL value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, NO); + [dict2 release]; +} + +- (void)testRemove { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBUInt64BoolDictionary *dict = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + BOOL value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, NO); + + // Remove again does nothing. + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, NO); + + [dict removeValueForKey:34ULL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertFalse([dict valueForKey:33ULL value:NULL]); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBUInt64BoolDictionary *dict = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + BOOL value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, NO); + + [dict setValue:NO forKey:31ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, NO); + + [dict setValue:YES forKey:34ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, YES); + + const uint64_t kKeys2[] = { 32ULL, 33ULL }; + const BOOL kValues2[] = { NO, YES }; + GPBUInt64BoolDictionary *dict2 = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, YES); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt64 -> Float + +@interface GPBUInt64FloatDictionaryTests : XCTestCase +@end + +@implementation GPBUInt64FloatDictionaryTests + +- (void)testEmpty { + GPBUInt64FloatDictionary *dict = [[GPBUInt64FloatDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt64FloatDictionary *dict = [GPBUInt64FloatDictionary dictionaryWithValue:500.f forKey:31ULL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + float value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, float aValue, BOOL *stop) { + XCTAssertEqual(aKey, 31ULL); + XCTAssertEqual(aValue, 500.f); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL }; + const float kValues[] = { 500.f, 501.f, 502.f }; + GPBUInt64FloatDictionary *dict = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + float value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + __block NSUInteger idx = 0; + uint64_t *seenKeys = malloc(3 * sizeof(uint64_t)); + float *seenValues = malloc(3 * sizeof(float)); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, float aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL }; + const float kValues1[] = { 500.f, 501.f, 502.f }; + const float kValues2[] = { 500.f, 503.f, 502.f }; + const float kValues3[] = { 500.f, 501.f, 502.f, 503.f }; + GPBUInt64FloatDictionary *dict1 = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt64FloatDictionary *dict1prime = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt64FloatDictionary *dict2 = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt64FloatDictionary *dict3 = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt64FloatDictionary *dict4 = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBUInt64FloatDictionary *dict = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64FloatDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64FloatDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBUInt64FloatDictionary *dict = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64FloatDictionary *dict2 = + [GPBUInt64FloatDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt64FloatDictionary *dict = [GPBUInt64FloatDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:500.f forKey:31ULL]; + XCTAssertEqual(dict.count, 1U); + + const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL }; + const float kValues[] = { 501.f, 502.f, 503.f }; + GPBUInt64FloatDictionary *dict2 = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + float value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 503.f); + [dict2 release]; +} + +- (void)testRemove { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBUInt64FloatDictionary *dict = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + float value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 503.f); + + // Remove again does nothing. + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 503.f); + + [dict removeValueForKey:34ULL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertFalse([dict valueForKey:33ULL value:NULL]); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBUInt64FloatDictionary *dict = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + float value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 503.f); + + [dict setValue:503.f forKey:31ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 503.f); + + [dict setValue:501.f forKey:34ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 501.f); + + const uint64_t kKeys2[] = { 32ULL, 33ULL }; + const float kValues2[] = { 502.f, 500.f }; + GPBUInt64FloatDictionary *dict2 = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 501.f); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt64 -> Double + +@interface GPBUInt64DoubleDictionaryTests : XCTestCase +@end + +@implementation GPBUInt64DoubleDictionaryTests + +- (void)testEmpty { + GPBUInt64DoubleDictionary *dict = [[GPBUInt64DoubleDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt64DoubleDictionary *dict = [GPBUInt64DoubleDictionary dictionaryWithValue:600. forKey:31ULL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + double value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, double aValue, BOOL *stop) { + XCTAssertEqual(aKey, 31ULL); + XCTAssertEqual(aValue, 600.); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL }; + const double kValues[] = { 600., 601., 602. }; + GPBUInt64DoubleDictionary *dict = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + double value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + __block NSUInteger idx = 0; + uint64_t *seenKeys = malloc(3 * sizeof(uint64_t)); + double *seenValues = malloc(3 * sizeof(double)); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, double aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL }; + const double kValues1[] = { 600., 601., 602. }; + const double kValues2[] = { 600., 603., 602. }; + const double kValues3[] = { 600., 601., 602., 603. }; + GPBUInt64DoubleDictionary *dict1 = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt64DoubleDictionary *dict1prime = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt64DoubleDictionary *dict2 = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt64DoubleDictionary *dict3 = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt64DoubleDictionary *dict4 = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBUInt64DoubleDictionary *dict = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64DoubleDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64DoubleDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBUInt64DoubleDictionary *dict = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64DoubleDictionary *dict2 = + [GPBUInt64DoubleDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt64DoubleDictionary *dict = [GPBUInt64DoubleDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:600. forKey:31ULL]; + XCTAssertEqual(dict.count, 1U); + + const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL }; + const double kValues[] = { 601., 602., 603. }; + GPBUInt64DoubleDictionary *dict2 = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + double value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 603.); + [dict2 release]; +} + +- (void)testRemove { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBUInt64DoubleDictionary *dict = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + double value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 603.); + + // Remove again does nothing. + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 603.); + + [dict removeValueForKey:34ULL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertFalse([dict valueForKey:33ULL value:NULL]); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBUInt64DoubleDictionary *dict = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + double value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 603.); + + [dict setValue:603. forKey:31ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 603.); + + [dict setValue:601. forKey:34ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 601.); + + const uint64_t kKeys2[] = { 32ULL, 33ULL }; + const double kValues2[] = { 602., 600. }; + GPBUInt64DoubleDictionary *dict2 = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 601.); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt64 -> Enum + +@interface GPBUInt64EnumDictionaryTests : XCTestCase +@end + +@implementation GPBUInt64EnumDictionaryTests + +- (void)testEmpty { + GPBUInt64EnumDictionary *dict = [[GPBUInt64EnumDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt64EnumDictionary *dict = [GPBUInt64EnumDictionary dictionaryWithValue:700 forKey:31ULL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 31ULL); + XCTAssertEqual(aValue, 700); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL }; + const int32_t kValues[] = { 700, 701, 702 }; + GPBUInt64EnumDictionary *dict = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + __block NSUInteger idx = 0; + uint64_t *seenKeys = malloc(3 * sizeof(uint64_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL }; + const int32_t kValues1[] = { 700, 701, 702 }; + const int32_t kValues2[] = { 700, 703, 702 }; + const int32_t kValues3[] = { 700, 701, 702, 703 }; + GPBUInt64EnumDictionary *dict1 = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt64EnumDictionary *dict1prime = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt64EnumDictionary *dict2 = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt64EnumDictionary *dict3 = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt64EnumDictionary *dict4 = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBUInt64EnumDictionary *dict = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64EnumDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBUInt64EnumDictionary *dict = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64EnumDictionary *dict2 = + [GPBUInt64EnumDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt64EnumDictionary *dict = [GPBUInt64EnumDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:700 forKey:31ULL]; + XCTAssertEqual(dict.count, 1U); + + const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 701, 702, 703 }; + GPBUInt64EnumDictionary *dict2 = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 703); + [dict2 release]; +} + +- (void)testRemove { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBUInt64EnumDictionary *dict = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 703); + + // Remove again does nothing. + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 703); + + [dict removeValueForKey:34ULL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertFalse([dict valueForKey:33ULL value:NULL]); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBUInt64EnumDictionary *dict = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 703); + + [dict setValue:703 forKey:31ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 703); + + [dict setValue:701 forKey:34ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 701); + + const uint64_t kKeys2[] = { 32ULL, 33ULL }; + const int32_t kValues2[] = { 702, 700 }; + GPBUInt64EnumDictionary *dict2 = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 701); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt64 -> Enum (Unknown Enums) + +@interface GPBUInt64EnumDictionaryUnknownEnumTests : XCTestCase +@end + +@implementation GPBUInt64EnumDictionaryUnknownEnumTests + +- (void)testRawBasics { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL }; + const int32_t kValues[] = { 700, 801, 702 }; + GPBUInt64EnumDictionary *dict = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue(dict.validationFunc == TestingEnum_IsValidValue); // Pointer comparison + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:31ULL rawValue:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:32ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:32ULL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:33ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:33ULL rawValue:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:34ULL rawValue:NULL]); + + __block NSUInteger idx = 0; + uint64_t *seenKeys = malloc(3 * sizeof(uint64_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + if (i == 1) { + XCTAssertEqual(kGPBUnrecognizedEnumeratorValue, seenValues[j], @"i = %d, j = %d", i, j); + } else { + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + idx = 0; + [dict enumerateKeysAndRawValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndRawValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEqualityWithUnknowns { + const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL }; + const int32_t kValues1[] = { 700, 801, 702 }; // Unknown + const int32_t kValues2[] = { 700, 803, 702 }; // Unknown + const int32_t kValues3[] = { 700, 801, 702, 803 }; // Unknowns + GPBUInt64EnumDictionary *dict1 = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt64EnumDictionary *dict1prime = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt64EnumDictionary *dict2 = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt64EnumDictionary *dict3 = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt64EnumDictionary *dict4 = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopyWithUnknowns { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknown + GPBUInt64EnumDictionary *dict = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + XCTAssertEqualObjects(dict, dict2); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBUInt64EnumDictionary *dict = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64EnumDictionary *dict2 = + [GPBUInt64EnumDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + [dict release]; +} + +- (void)testUnknownAdds { + GPBUInt64EnumDictionary *dict = + [GPBUInt64EnumDictionary dictionaryWithValidationFunction:TestingEnum_IsValidValue]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + XCTAssertThrowsSpecificNamed([dict setValue:801 forKey:32ULL], // Unknown + NSException, NSInvalidArgumentException); + XCTAssertEqual(dict.count, 0U); + [dict setRawValue:801 forKey:32ULL]; // Unknown + XCTAssertEqual(dict.count, 1U); + + const uint64_t kKeys[] = { 31ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 700, 702, 803 }; // Unknown + GPBUInt64EnumDictionary *dict2 = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:32ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:32ULL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:34ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:34ULL rawValue:&value]); + XCTAssertEqual(value, 803); + [dict2 release]; +} + +- (void)testUnknownRemove { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBUInt64EnumDictionary *dict = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:34ULL rawValue:&value]); + XCTAssertEqual(value, 803); + + // Remove again does nothing. + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:34ULL rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict removeValueForKey:34ULL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertFalse([dict valueForKey:33ULL value:NULL]); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutationUnknowns { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBUInt64EnumDictionary *dict = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:32ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:32ULL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:34ULL rawValue:&value]); + XCTAssertEqual(value, 803); + + XCTAssertThrowsSpecificNamed([dict setValue:803 forKey:31ULL], // Unknown + NSException, NSInvalidArgumentException); + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:32ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:32ULL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:34ULL rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict setRawValue:803 forKey:31ULL]; // Unknown + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:31ULL rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:32ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:32ULL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:34ULL rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict setRawValue:700 forKey:34ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:31ULL rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:32ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:32ULL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 700); + + const uint64_t kKeys2[] = { 32ULL, 33ULL }; + const int32_t kValues2[] = { 702, 801 }; // Unknown + GPBUInt64EnumDictionary *dict2 = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:31ULL rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:33ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:33ULL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 700); + + [dict2 release]; + [dict release]; +} + +- (void)testCopyUnknowns { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 700, 801, 702, 803 }; + GPBUInt64EnumDictionary *dict = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64EnumDictionary class]]); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt64 -> Object + +@interface GPBUInt64ObjectDictionaryTests : XCTestCase +@end + +@implementation GPBUInt64ObjectDictionaryTests + +- (void)testEmpty { + GPBUInt64ObjectDictionary *dict = [[GPBUInt64ObjectDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertNil([dict valueForKey:31ULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, id aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt64ObjectDictionary *dict = [GPBUInt64ObjectDictionary dictionaryWithValue:@"abc" forKey:31ULL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + XCTAssertEqualObjects([dict valueForKey:31ULL], @"abc"); + XCTAssertNil([dict valueForKey:32ULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, id aValue, BOOL *stop) { + XCTAssertEqual(aKey, 31ULL); + XCTAssertEqualObjects(aValue, @"abc"); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL }; + const id kValues[] = { @"abc", @"def", @"ghi" }; + GPBUInt64ObjectDictionary *dict = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:31ULL], @"abc"); + XCTAssertEqualObjects([dict valueForKey:32ULL], @"def"); + XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi"); + XCTAssertNil([dict valueForKey:34ULL]); + + __block NSUInteger idx = 0; + uint64_t *seenKeys = malloc(3 * sizeof(uint64_t)); + id *seenValues = malloc(3 * sizeof(id)); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, id aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqualObjects(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, id aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL }; + const id kValues1[] = { @"abc", @"def", @"ghi" }; + const id kValues2[] = { @"abc", @"jkl", @"ghi" }; + const id kValues3[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBUInt64ObjectDictionary *dict1 = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt64ObjectDictionary *dict1prime = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt64ObjectDictionary *dict2 = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt64ObjectDictionary *dict3 = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt64ObjectDictionary *dict4 = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBUInt64ObjectDictionary *dict = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64ObjectDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64ObjectDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBUInt64ObjectDictionary *dict = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64ObjectDictionary *dict2 = + [GPBUInt64ObjectDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt64ObjectDictionary *dict = [GPBUInt64ObjectDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:@"abc" forKey:31ULL]; + XCTAssertEqual(dict.count, 1U); + + const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL }; + const id kValues[] = { @"def", @"ghi", @"jkl" }; + GPBUInt64ObjectDictionary *dict2 = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + XCTAssertEqualObjects([dict valueForKey:31ULL], @"abc"); + XCTAssertEqualObjects([dict valueForKey:32ULL], @"def"); + XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:34ULL], @"jkl"); + [dict2 release]; +} + +- (void)testRemove { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBUInt64ObjectDictionary *dict = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:31ULL], @"abc"); + XCTAssertNil([dict valueForKey:32ULL]); + XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:34ULL], @"jkl"); + + // Remove again does nothing. + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:31ULL], @"abc"); + XCTAssertNil([dict valueForKey:32ULL]); + XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:34ULL], @"jkl"); + + [dict removeValueForKey:34ULL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertEqualObjects([dict valueForKey:31ULL], @"abc"); + XCTAssertNil([dict valueForKey:32ULL]); + XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi"); + XCTAssertNil([dict valueForKey:34ULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertNil([dict valueForKey:31ULL]); + XCTAssertNil([dict valueForKey:32ULL]); + XCTAssertNil([dict valueForKey:33ULL]); + XCTAssertNil([dict valueForKey:34ULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBUInt64ObjectDictionary *dict = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:31ULL], @"abc"); + XCTAssertEqualObjects([dict valueForKey:32ULL], @"def"); + XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:34ULL], @"jkl"); + + [dict setValue:@"jkl" forKey:31ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:31ULL], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:32ULL], @"def"); + XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:34ULL], @"jkl"); + + [dict setValue:@"def" forKey:34ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:31ULL], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:32ULL], @"def"); + XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:34ULL], @"def"); + + const uint64_t kKeys2[] = { 32ULL, 33ULL }; + const id kValues2[] = { @"ghi", @"abc" }; + GPBUInt64ObjectDictionary *dict2 = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:31ULL], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:32ULL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:33ULL], @"abc"); + XCTAssertEqualObjects([dict valueForKey:34ULL], @"def"); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND-END TEST_FOR_POD_KEY(UInt64, uint64_t, 31ULL, 32ULL, 33ULL, 34ULL) diff --git a/objectivec/Tests/GPBDictionaryTests.pddm b/objectivec/Tests/GPBDictionaryTests.pddm new file mode 100644 index 00000000..39793e03 --- /dev/null +++ b/objectivec/Tests/GPBDictionaryTests.pddm @@ -0,0 +1,1044 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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. + +//%PDDM-DEFINE TEST_FOR_POD_KEY(KEY_NAME, KEY_TYPE, KEY1, KEY2, KEY3, KEY4) +//%TESTS_FOR_POD_VALUES(KEY_NAME, KEY_TYPE, , , KEY1, KEY2, KEY3, KEY4) +//%TESTS_FOR_POD_KEY_OBJECT_VALUE(KEY_NAME, KEY_TYPE, KEY1, KEY2, KEY3, KEY4, Object, id, @"abc", @"def", @"ghi", @"jkl") + +//%PDDM-DEFINE TESTS_FOR_POD_VALUES(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4) +//%TEST_HELPERS(KEY_NAME, KEY_TYPE, KisP) +//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, UInt32, uint32_t, , 100U, 101U, 102U, 103U) +//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Int32, int32_t, , 200, 201, 202, 203) +//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, UInt64, uint64_t, , 300U, 301U, 302U, 303U) +//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Int64, int64_t, , 400, 401, 402, 403) +//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Bool, BOOL, , YES, YES, NO, NO) +//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Float, float, , 500.f, 501.f, 502.f, 503.f) +//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Double, double, , 600., 601., 602., 603.) +//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Enum, int32_t, Raw, 700, 701, 702, 703) +//%TESTS_FOR_ENUM_VALUE_RAW_ADDITIONS(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4) + +//%PDDM-DEFINE TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, VACCESSOR, VAL1, VAL2, VAL3, VAL4) +//%TESTS_COMMON(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, , POD, VACCESSOR, VAL1, VAL2, VAL3, VAL4) + +//%PDDM-DEFINE TESTS_FOR_POD_KEY_OBJECT_VALUE(KEY_NAME, KEY_TYPE, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, VAL1, VAL2, VAL3, VAL4) +//%TESTS_COMMON(KEY_NAME, KEY_TYPE, , , KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, Objects, OBJECT, , VAL1, VAL2, VAL3, VAL4) + +//%PDDM-DEFINE TESTS_COMMON(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, VSUFFIX, VHELPER, VACCESSOR, VAL1, VAL2, VAL3, VAL4) +//%#pragma mark - KEY_NAME -> VALUE_NAME +//% +//%@interface GPB##KEY_NAME##VALUE_NAME##DictionaryTests : XCTestCase +//%@end +//% +//%@implementation GPB##KEY_NAME##VALUE_NAME##DictionaryTests +//% +//%- (void)testEmpty { +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] init]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 0U); +//%VALUE_NOT_FOUND##VHELPER(dict, KEY1) +//% [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { +//% #pragma unused(aKey, aValue, stop) +//% XCTFail(@"Shouldn't get here!"); +//% }]; +//% [dict release]; +//%} +//% +//%- (void)testOne { +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWithValue:VAL1 forKey:KEY1]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 1U); +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//% [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { +//% XCTAssertEqual##KSUFFIX(aKey, KEY1); +//% XCTAssertEqual##VSUFFIX(aValue, VAL1); +//% XCTAssertNotEqual(stop, NULL); +//% }]; +//%} +//% +//%- (void)testBasics { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 3U); +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY4) +//% +//% __block NSUInteger idx = 0; +//% KEY_TYPE KisP##*seenKeys = malloc(3 * sizeof(KEY_TYPE##KisP)); +//% VALUE_TYPE *seenValues = malloc(3 * sizeof(VALUE_TYPE)); +//% [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { +//% XCTAssertLessThan(idx, 3U); +//% seenKeys[idx] = aKey; +//% seenValues[idx] = aValue; +//% XCTAssertNotEqual(stop, NULL); +//% ++idx; +//% }]; +//% for (int i = 0; i < 3; ++i) { +//% BOOL foundKey = NO; +//% for (int j = 0; (j < 3) && !foundKey; ++j) { +//% if (COMPARE_KEYS##KSUFFIX(kKeys[i], seenKeys[j])) { +//% foundKey = YES; +//% XCTAssertEqual##VSUFFIX(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); +//% } +//% } +//% XCTAssertTrue(foundKey, @"i = %d", i); +//% } +//% free(seenKeys); +//% free(seenValues); +//% +//% // Stopping the enumeration. +//% idx = 0; +//% [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { +//% #pragma unused(aKey, aValue) +//% if (idx == 1) *stop = YES; +//% XCTAssertNotEqual(idx, 2U); +//% ++idx; +//% }]; +//% [dict release]; +//%} +//% +//%- (void)testEquality { +//% const KEY_TYPE KisP##kKeys1[] = { KEY1, KEY2, KEY3, KEY4 }; +//% const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY1, KEY4 }; +//% const VALUE_TYPE kValues1[] = { VAL1, VAL2, VAL3 }; +//% const VALUE_TYPE kValues2[] = { VAL1, VAL4, VAL3 }; +//% const VALUE_TYPE kValues3[] = { VAL1, VAL2, VAL3, VAL4 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict1 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues1 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertNotNil(dict1); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict1prime = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues1 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertNotNil(dict1prime); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues2 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues2)]; +//% XCTAssertNotNil(dict2); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict3 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues1 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys2 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertNotNil(dict3); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict4 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues3 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues3)]; +//% XCTAssertNotNil(dict4); +//% +//% // 1/1Prime should be different objects, but equal. +//% XCTAssertNotEqual(dict1, dict1prime); +//% XCTAssertEqualObjects(dict1, dict1prime); +//% // Equal, so they must have same hash. +//% XCTAssertEqual([dict1 hash], [dict1prime hash]); +//% +//% // 2 is save keys, different values; not equal. +//% XCTAssertNotEqualObjects(dict1, dict2); +//% +//% // 3 is different keys, samae values; not equal. +//% XCTAssertNotEqualObjects(dict1, dict3); +//% +//% // 4 extra pair; not equal +//% XCTAssertNotEqualObjects(dict1, dict4); +//% +//% [dict1 release]; +//% [dict1prime release]; +//% [dict2 release]; +//% [dict3 release]; +//% [dict4 release]; +//%} +//% +//%- (void)testCopy { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = [dict copy]; +//% XCTAssertNotNil(dict2); +//% +//% // Should be new object but equal. +//% XCTAssertNotEqual(dict, dict2); +//% XCTAssertEqualObjects(dict, dict2); +//% XCTAssertTrue([dict2 isKindOfClass:[GPB##KEY_NAME##VALUE_NAME##Dictionary class]]); +//% +//% [dict2 release]; +//% [dict release]; +//%} +//% +//%- (void)testDictionaryFromDictionary { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWithDictionary:dict]; +//% XCTAssertNotNil(dict2); +//% +//% // Should be new pointer, but equal objects. +//% XCTAssertNotEqual(dict, dict2); +//% XCTAssertEqualObjects(dict, dict2); +//% [dict release]; +//%} +//% +//%- (void)testAdds { +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionary]; +//% XCTAssertNotNil(dict); +//% +//% XCTAssertEqual(dict.count, 0U); +//% [dict setValue:VAL1 forKey:KEY1]; +//% XCTAssertEqual(dict.count, 1U); +//% +//% const KEY_TYPE KisP##kKeys[] = { KEY2, KEY3, KEY4 }; +//% const VALUE_TYPE kValues[] = { VAL2, VAL3, VAL4 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict2); +//% [dict add##VACCESSOR##EntriesFromDictionary:dict2]; +//% XCTAssertEqual(dict.count, 4U); +//% +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL4) +//% [dict2 release]; +//%} +//% +//%- (void)testRemove { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 4U); +//% +//% [dict removeValueForKey:KEY2]; +//% XCTAssertEqual(dict.count, 3U); +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL4) +//% +//% // Remove again does nothing. +//% [dict removeValueForKey:KEY2]; +//% XCTAssertEqual(dict.count, 3U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL4) +//% +//% [dict removeValueForKey:KEY4]; +//% XCTAssertEqual(dict.count, 2U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY4) +//% +//% [dict removeAll]; +//% XCTAssertEqual(dict.count, 0U); +//%VALUE_NOT_FOUND##VHELPER(dict, KEY1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY3) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY4) +//% [dict release]; +//%} +//% +//%- (void)testInplaceMutation { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 4U); +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL4) +//% +//% [dict setValue:VAL4 forKey:KEY1]; +//% XCTAssertEqual(dict.count, 4U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL4) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL4) +//% +//% [dict setValue:VAL2 forKey:KEY4]; +//% XCTAssertEqual(dict.count, 4U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL4) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL2) +//% +//% const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY3 }; +//% const VALUE_TYPE kValues2[] = { VAL3, VAL1 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues2 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys2 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues2)]; +//% XCTAssertNotNil(dict2); +//% [dict add##VACCESSOR##EntriesFromDictionary:dict2]; +//% XCTAssertEqual(dict.count, 4U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL4) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL3) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL1) +//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL2) +//% +//% [dict2 release]; +//% [dict release]; +//%} +//% +//%@end +//% + +//%PDDM-DEFINE TESTS_FOR_ENUM_VALUE_RAW_ADDITIONS(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4) +//%TESTS_FOR_ENUM_VALUE_RAW_ADDITIONS2(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Enum, int32_t, , POD, 700, 801, 702, 803) +//%PDDM-DEFINE TESTS_FOR_ENUM_VALUE_RAW_ADDITIONS2(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, VSUFFIX, VHELPER, VAL1, VAL2, VAL3, VAL4) +//%#pragma mark - KEY_NAME -> VALUE_NAME (Unknown Enums) +//% +//%@interface GPB##KEY_NAME##VALUE_NAME##DictionaryUnknownEnumTests : XCTestCase +//%@end +//% +//%@implementation GPB##KEY_NAME##VALUE_NAME##DictionaryUnknownEnumTests +//% +//%- (void)testRawBasics { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 3U); +//% XCTAssertTrue(dict.validationFunc == TestingEnum_IsValidValue); // Pointer comparison +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_RAW_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%TEST_VALUE##VHELPER(dict, value, KEY2, kGPBUnrecognizedEnumeratorValue) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%RAW_VALUE_NOT_FOUND##VHELPER(dict, KEY4) +//% +//% __block NSUInteger idx = 0; +//% KEY_TYPE KisP##*seenKeys = malloc(3 * sizeof(KEY_TYPE##KisP)); +//% VALUE_TYPE *seenValues = malloc(3 * sizeof(VALUE_TYPE)); +//% [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { +//% XCTAssertLessThan(idx, 3U); +//% seenKeys[idx] = aKey; +//% seenValues[idx] = aValue; +//% XCTAssertNotEqual(stop, NULL); +//% ++idx; +//% }]; +//% for (int i = 0; i < 3; ++i) { +//% BOOL foundKey = NO; +//% for (int j = 0; (j < 3) && !foundKey; ++j) { +//% if (COMPARE_KEYS##KSUFFIX(kKeys[i], seenKeys[j])) { +//% foundKey = YES; +//% if (i == 1) { +//% XCTAssertEqual##VSUFFIX(kGPBUnrecognizedEnumeratorValue, seenValues[j], @"i = %d, j = %d", i, j); +//% } else { +//% XCTAssertEqual##VSUFFIX(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); +//% } +//% } +//% } +//% XCTAssertTrue(foundKey, @"i = %d", i); +//% } +//% idx = 0; +//% [dict enumerateKeysAndRawValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { +//% XCTAssertLessThan(idx, 3U); +//% seenKeys[idx] = aKey; +//% seenValues[idx] = aValue; +//% XCTAssertNotEqual(stop, NULL); +//% ++idx; +//% }]; +//% for (int i = 0; i < 3; ++i) { +//% BOOL foundKey = NO; +//% for (int j = 0; (j < 3) && !foundKey; ++j) { +//% if (COMPARE_KEYS##KSUFFIX(kKeys[i], seenKeys[j])) { +//% foundKey = YES; +//% XCTAssertEqual##VSUFFIX(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); +//% } +//% } +//% XCTAssertTrue(foundKey, @"i = %d", i); +//% } +//% free(seenKeys); +//% free(seenValues); +//% +//% // Stopping the enumeration. +//% idx = 0; +//% [dict enumerateKeysAndRawValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { +//% #pragma unused(aKey, aValue) +//% if (idx == 1) *stop = YES; +//% XCTAssertNotEqual(idx, 2U); +//% ++idx; +//% }]; +//% [dict release]; +//%} +//% +//%- (void)testEqualityWithUnknowns { +//% const KEY_TYPE KisP##kKeys1[] = { KEY1, KEY2, KEY3, KEY4 }; +//% const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY1, KEY4 }; +//% const VALUE_TYPE kValues1[] = { VAL1, VAL2, VAL3 }; // Unknown +//% const VALUE_TYPE kValues2[] = { VAL1, VAL4, VAL3 }; // Unknown +//% const VALUE_TYPE kValues3[] = { VAL1, VAL2, VAL3, VAL4 }; // Unknowns +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict1 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues1 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertNotNil(dict1); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict1prime = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues1 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertNotNil(dict1prime); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues2 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues2)]; +//% XCTAssertNotNil(dict2); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict3 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues1 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys2 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertNotNil(dict3); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict4 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues3 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues3)]; +//% XCTAssertNotNil(dict4); +//% +//% // 1/1Prime should be different objects, but equal. +//% XCTAssertNotEqual(dict1, dict1prime); +//% XCTAssertEqualObjects(dict1, dict1prime); +//% // Equal, so they must have same hash. +//% XCTAssertEqual([dict1 hash], [dict1prime hash]); +//% +//% // 2 is save keys, different values; not equal. +//% XCTAssertNotEqualObjects(dict1, dict2); +//% +//% // 3 is different keys, samae values; not equal. +//% XCTAssertNotEqualObjects(dict1, dict3); +//% +//% // 4 extra pair; not equal +//% XCTAssertNotEqualObjects(dict1, dict4); +//% +//% [dict1 release]; +//% [dict1prime release]; +//% [dict2 release]; +//% [dict3 release]; +//% [dict4 release]; +//%} +//% +//%- (void)testCopyWithUnknowns { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; // Unknown +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = [dict copy]; +//% XCTAssertNotNil(dict2); +//% +//% // Should be new pointer, but equal objects. +//% XCTAssertNotEqual(dict, dict2); +//% XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison +//% XCTAssertEqualObjects(dict, dict2); +//% +//% [dict2 release]; +//% [dict release]; +//%} +//% +//%- (void)testDictionaryFromDictionary { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; // Unknowns +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWithDictionary:dict]; +//% XCTAssertNotNil(dict2); +//% +//% // Should be new pointer, but equal objects. +//% XCTAssertNotEqual(dict, dict2); +//% XCTAssertEqualObjects(dict, dict2); +//% XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison +//% [dict release]; +//%} +//% +//%- (void)testUnknownAdds { +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWithValidationFunction:TestingEnum_IsValidValue]; +//% XCTAssertNotNil(dict); +//% +//% XCTAssertEqual(dict.count, 0U); +//% XCTAssertThrowsSpecificNamed([dict setValue:VAL2 forKey:KEY2], // Unknown +//% NSException, NSInvalidArgumentException); +//% XCTAssertEqual(dict.count, 0U); +//% [dict setRawValue:VAL2 forKey:KEY2]; // Unknown +//% XCTAssertEqual(dict.count, 1U); +//% +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY3, KEY4 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL3, VAL4 }; // Unknown +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict2); +//% [dict addRawEntriesFromDictionary:dict2]; +//% XCTAssertEqual(dict.count, 4U); +//% +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%TEST_VALUE##VHELPER(dict, value, KEY2, kGPBUnrecognizedEnumeratorValue) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_VALUE##VHELPER(dict, value, KEY4, kGPBUnrecognizedEnumeratorValue) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4) +//% [dict2 release]; +//%} +//% +//%- (void)testUnknownRemove { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; // Unknowns +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 4U); +//% +//% [dict removeValueForKey:KEY2]; +//% XCTAssertEqual(dict.count, 3U); +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4) +//% +//% // Remove again does nothing. +//% [dict removeValueForKey:KEY2]; +//% XCTAssertEqual(dict.count, 3U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4) +//% +//% [dict removeValueForKey:KEY4]; +//% XCTAssertEqual(dict.count, 2U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY4) +//% +//% [dict removeAll]; +//% XCTAssertEqual(dict.count, 0U); +//%VALUE_NOT_FOUND##VHELPER(dict, KEY1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY3) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY4) +//% [dict release]; +//%} +//% +//%- (void)testInplaceMutationUnknowns { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; // Unknowns +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 4U); +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4) +//% +//% XCTAssertThrowsSpecificNamed([dict setValue:VAL4 forKey:KEY1], // Unknown +//% NSException, NSInvalidArgumentException); +//% XCTAssertEqual(dict.count, 4U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4) +//% +//% [dict setRawValue:VAL4 forKey:KEY1]; // Unknown +//% XCTAssertEqual(dict.count, 4U); +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY1, VAL4) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4) +//% +//% [dict setRawValue:VAL1 forKey:KEY4]; +//% XCTAssertEqual(dict.count, 4U); +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY1, VAL4) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL1) +//% +//% const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY3 }; +//% const VALUE_TYPE kValues2[] = { VAL3, VAL2 }; // Unknown +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues2 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys2 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues2)]; +//% XCTAssertNotNil(dict2); +//% [dict addRawEntriesFromDictionary:dict2]; +//% XCTAssertEqual(dict.count, 4U); +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY1, VAL4) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL3) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY3, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL1) +//% +//% [dict2 release]; +//% [dict release]; +//%} +//% +//%- (void)testCopyUnknowns { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = [dict copy]; +//% XCTAssertNotNil(dict2); +//% +//% // Should be new pointer, but equal objects. +//% XCTAssertNotEqual(dict, dict2); +//% XCTAssertEqualObjects(dict, dict2); +//% XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison +//% XCTAssertTrue([dict2 isKindOfClass:[GPB##KEY_NAME##VALUE_NAME##Dictionary class]]); +//% +//% [dict2 release]; +//% [dict release]; +//%} +//% +//%@end +//% + +// +// Helpers for PODs +// + +//%PDDM-DEFINE DECLARE_VALUE_STORAGEPOD(VALUE_TYPE, NAME) +//% VALUE_TYPE NAME; +//% +//%PDDM-DEFINE VALUE_NOT_FOUNDPOD(DICT, KEY) +//% XCTAssertFalse([DICT valueForKey:KEY value:NULL]); +//%PDDM-DEFINE TEST_VALUEPOD(DICT, STORAGE, KEY, VALUE) +//% XCTAssertTrue([DICT valueForKey:KEY value:NULL]); +//% XCTAssertTrue([DICT valueForKey:KEY value:&STORAGE]); +//% XCTAssertEqual(STORAGE, VALUE); +//%PDDM-DEFINE COMPARE_KEYS(KEY1, KEY2) +//%KEY1 == KEY2 +//%PDDM-DEFINE RAW_VALUE_NOT_FOUNDPOD(DICT, KEY) +//% XCTAssertFalse([DICT valueForKey:KEY rawValue:NULL]); +//%PDDM-DEFINE TEST_RAW_VALUEPOD(DICT, STORAGE, KEY, VALUE) +//% XCTAssertTrue([DICT valueForKey:KEY rawValue:NULL]); +//% XCTAssertTrue([DICT valueForKey:KEY rawValue:&STORAGE]); +//% XCTAssertEqual(STORAGE, VALUE); + +// +// Helpers for Objects +// + +//%PDDM-DEFINE DECLARE_VALUE_STORAGEOBJECT(VALUE_TYPE, NAME) +// Empty +//%PDDM-DEFINE VALUE_NOT_FOUNDOBJECT(DICT, KEY) +//% XCTAssertNil([DICT valueForKey:KEY]); +//%PDDM-DEFINE TEST_VALUEOBJECT(DICT, STORAGE, KEY, VALUE) +//% XCTAssertEqualObjects([DICT valueForKey:KEY], VALUE); +//%PDDM-DEFINE COMPARE_KEYSObjects(KEY1, KEY2) +//%[KEY1 isEqual:KEY2] + +// +// Helpers for tests. +// + +//%PDDM-DEFINE TEST_HELPERS(KEY_NAME, KEY_TYPE, KisP) +//%#ifndef GPBARRAYSIZE +//%#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0])))) +//%#endif // GPBARRAYSIZE +//% +//%// To let the testing macros work, add some extra methods to simplify things. +//%@interface GPB##KEY_NAME##EnumDictionary (TestingTweak) +//%+ (instancetype)dictionaryWithValue:(int32_t)value forKey:(KEY_TYPE##KisP$S##KisP)key; +//%- (instancetype)initWithValues:(const int32_t [])values +//% forKeys:(const KEY_TYPE##KisP$S##KisP [])keys +//% count:(NSUInteger)count; +//%@end +//% +//%static BOOL TestingEnum_IsValidValue(int32_t value) { +//% switch (value) { +//% case 700: +//% case 701: +//% case 702: +//% case 703: +//% return YES; +//% default: +//% return NO; +//% } +//%} +//% +//%@implementation GPB##KEY_NAME##EnumDictionary (TestingTweak) +//%+ (instancetype)dictionaryWithValue:(int32_t)value forKey:(KEY_TYPE##KisP$S##KisP)key { +//% // Cast is needed to compiler knows what class we are invoking initWithValues: on to get the +//% // type correct. +//% return [[(GPB##KEY_NAME##EnumDictionary*)[self alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S rawValues:&value +//% KEY_NAME$S forKeys:&key +//% KEY_NAME$S count:1] autorelease]; +//%} +//%- (instancetype)initWithValues:(const int32_t [])values +//% forKeys:(const KEY_TYPE##KisP$S##KisP [])keys +//% count:(NSUInteger)count { +//% return [self initWithValidationFunction:TestingEnum_IsValidValue +//% rawValues:values +//% forKeys:keys +//% count:count]; +//%} +//%@end +//% +//% + + +// +// BOOL test macros +// +//TODO(thomasvl): enum tests + +//%PDDM-DEFINE BOOL_TESTS_FOR_POD_VALUE(VALUE_NAME, VALUE_TYPE, VAL1, VAL2) +//%BOOL_TESTS_COMMON(Bool, BOOL, , , YES, NO, VALUE_NAME, VALUE_TYPE, , POD, VAL1, VAL2) + +//%PDDM-DEFINE TESTS_FOR_BOOL_KEY_OBJECT_VALUE(VALUE_NAME, VALUE_TYPE, VAL1, VAL2) +//%BOOL_TESTS_COMMON(Bool, BOOL, , , YES, NO, VALUE_NAME, VALUE_TYPE, Objects, OBJECT, VAL1, VAL2) + +//%PDDM-DEFINE BOOL_TESTS_COMMON(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, VALUE_NAME, VALUE_TYPE, VSUFFIX, VHELPER, VAL1, VAL2) +//%#pragma mark - KEY_NAME -> VALUE_NAME +//% +//%@interface GPB##KEY_NAME##VALUE_NAME##DictionaryTests : XCTestCase +//%@end +//% +//%@implementation GPB##KEY_NAME##VALUE_NAME##DictionaryTests +//% +//%- (void)testEmpty { +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] init]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 0U); +//%VALUE_NOT_FOUND##VHELPER(dict, KEY1) +//% [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { +//% #pragma unused(aKey, aValue, stop) +//% XCTFail(@"Shouldn't get here!"); +//% }]; +//% [dict release]; +//%} +//% +//%- (void)testOne { +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWithValue:VAL1 forKey:KEY1]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 1U); +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//% [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { +//% XCTAssertEqual##KSUFFIX(aKey, KEY1); +//% XCTAssertEqual##VSUFFIX(aValue, VAL1); +//% XCTAssertNotEqual(stop, NULL); +//% }]; +//%} +//% +//%- (void)testBasics { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 2U); +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2) +//% +//% __block NSUInteger idx = 0; +//% KEY_TYPE KisP##*seenKeys = malloc(2 * sizeof(KEY_TYPE##KisP)); +//% VALUE_TYPE *seenValues = malloc(2 * sizeof(VALUE_TYPE)); +//% [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { +//% XCTAssertLessThan(idx, 2U); +//% seenKeys[idx] = aKey; +//% seenValues[idx] = aValue; +//% XCTAssertNotEqual(stop, NULL); +//% ++idx; +//% }]; +//% for (int i = 0; i < 2; ++i) { +//% BOOL foundKey = NO; +//% for (int j = 0; (j < 2) && !foundKey; ++j) { +//% if (COMPARE_KEYS##KSUFFIX(kKeys[i], seenKeys[j])) { +//% foundKey = YES; +//% XCTAssertEqual##VSUFFIX(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); +//% } +//% } +//% XCTAssertTrue(foundKey, @"i = %d", i); +//% } +//% free(seenKeys); +//% free(seenValues); +//% +//% // Stopping the enumeration. +//% idx = 0; +//% [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { +//% #pragma unused(aKey, aValue) +//% if (idx == 0) *stop = YES; +//% XCTAssertNotEqual(idx, 2U); +//% ++idx; +//% }]; +//% [dict release]; +//%} +//% +//%- (void)testEquality { +//% const KEY_TYPE KisP##kKeys1[] = { KEY1, KEY2 }; +//% const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY1 }; +//% const VALUE_TYPE kValues1[] = { VAL1, VAL2 }; +//% const VALUE_TYPE kValues2[] = { VAL2, VAL1 }; +//% const VALUE_TYPE kValues3[] = { VAL2 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict1 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues1 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertNotNil(dict1); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict1prime = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues1 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertNotNil(dict1prime); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues2 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues2)]; +//% XCTAssertNotNil(dict2); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict3 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues1 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys2 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertNotNil(dict3); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict4 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues3 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues3)]; +//% XCTAssertNotNil(dict4); +//% +//% // 1/1Prime should be different objects, but equal. +//% XCTAssertNotEqual(dict1, dict1prime); +//% XCTAssertEqualObjects(dict1, dict1prime); +//% // Equal, so they must have same hash. +//% XCTAssertEqual([dict1 hash], [dict1prime hash]); +//% +//% // 2 is save keys, different values; not equal. +//% XCTAssertNotEqualObjects(dict1, dict2); +//% +//% // 3 is different keys, samae values; not equal. +//% XCTAssertNotEqualObjects(dict1, dict3); +//% +//% // 4 Fewer pairs; not equal +//% XCTAssertNotEqualObjects(dict1, dict4); +//% +//% [dict1 release]; +//% [dict1prime release]; +//% [dict2 release]; +//% [dict3 release]; +//% [dict4 release]; +//%} +//% +//%- (void)testCopy { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = [dict copy]; +//% XCTAssertNotNil(dict2); +//% +//% // Should be new object but equal. +//% XCTAssertNotEqual(dict, dict2); +//% XCTAssertEqualObjects(dict, dict2); +//% XCTAssertTrue([dict2 isKindOfClass:[GPB##KEY_NAME##VALUE_NAME##Dictionary class]]); +//% +//% [dict2 release]; +//% [dict release]; +//%} +//% +//%- (void)testDictionaryFromDictionary { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWithDictionary:dict]; +//% XCTAssertNotNil(dict2); +//% +//% // Should be new pointer, but equal objects. +//% XCTAssertNotEqual(dict, dict2); +//% XCTAssertEqualObjects(dict, dict2); +//% [dict release]; +//%} +//% +//%- (void)testAdds { +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionary]; +//% XCTAssertNotNil(dict); +//% +//% XCTAssertEqual(dict.count, 0U); +//% [dict setValue:VAL1 forKey:KEY1]; +//% XCTAssertEqual(dict.count, 1U); +//% +//% const KEY_TYPE KisP##kKeys[] = { KEY2 }; +//% const VALUE_TYPE kValues[] = { VAL2 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict2); +//% [dict addEntriesFromDictionary:dict2]; +//% XCTAssertEqual(dict.count, 2U); +//% +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2) +//% [dict2 release]; +//%} +//% +//%- (void)testRemove { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2}; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 2U); +//% +//% [dict removeValueForKey:KEY2]; +//% XCTAssertEqual(dict.count, 1U); +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//% +//% // Remove again does nothing. +//% [dict removeValueForKey:KEY2]; +//% XCTAssertEqual(dict.count, 1U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//% +//% [dict removeAll]; +//% XCTAssertEqual(dict.count, 0U); +//%VALUE_NOT_FOUND##VHELPER(dict, KEY1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//% [dict release]; +//%} +//% +//%- (void)testInplaceMutation { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 2U); +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2) +//% +//% [dict setValue:VAL2 forKey:KEY1]; +//% XCTAssertEqual(dict.count, 2U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2) +//% +//% [dict setValue:VAL1 forKey:KEY2]; +//% XCTAssertEqual(dict.count, 2U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL1) +//% +//% const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY1 }; +//% const VALUE_TYPE kValues2[] = { VAL2, VAL1 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues2 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys2 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues2)]; +//% XCTAssertNotNil(dict2); +//% [dict addEntriesFromDictionary:dict2]; +//% XCTAssertEqual(dict.count, 2U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2) +//% +//% [dict2 release]; +//% [dict release]; +//%} +//% +//%@end +//% + diff --git a/objectivec/Tests/GPBFilteredMessageTests.m b/objectivec/Tests/GPBFilteredMessageTests.m new file mode 100644 index 00000000..b0588837 --- /dev/null +++ b/objectivec/Tests/GPBFilteredMessageTests.m @@ -0,0 +1,98 @@ +// 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. + +// Tests our filter system for ObjC. +// The proto being filtered is unittest_filter.proto. +// The filter file is Filter.txt. + +#import "GPBTestUtilities.h" + +#import "google/protobuf/UnittestFilter.pbobjc.h" + +// If we get an error about this already being defined, it is most likely +// because of an error in protoc which is supposed to be filtering +// the Remove message. +enum { Other_FieldNumber_B = 0 }; + +@interface FilteredMessageTests : GPBTestCase +@end + +@implementation FilteredMessageTests + +- (void)testEnumFiltering { + // If compile fails here it is because protoc did not generate KeepEnum. + XCTAssertTrue(KeepEnum_IsValidValue(KeepEnum_KeepValue)); + XCTAssertNotNil(KeepEnum_EnumDescriptor()); + + // If compile fails here it is because protoc did not generate + // KeepEnumInsideEnum and is probably due to nested enum handling being + // broken. + XCTAssertTrue(RemoveEnumMessage_KeepEnumInside_IsValidValue( + RemoveEnumMessage_KeepEnumInside_KeepValue)); + XCTAssertNotNil(RemoveEnumMessage_KeepEnumInside_EnumDescriptor()); +} + +- (void)testMessageFiltering { + // Messages that should be generated. + XCTAssertNil([UnittestFilterRoot extensionRegistry]); + XCTAssertNotNil([[[Keep alloc] init] autorelease]); + XCTAssertNotNil([[[Other alloc] init] autorelease]); + XCTAssertNotNil([[[RemoveJustKidding alloc] init] autorelease]); + XCTAssertNotNil( + [[[RemoveEnumMessage_KeepNestedInside alloc] init] autorelease]); + + // Messages that should not be generated + XCTAssertNil(NSClassFromString(@"Remove")); + XCTAssertNil(NSClassFromString(@"RemoveEnumMessage")); + XCTAssertNil(NSClassFromString(@"RemoveEnumMessage_RemoveNestedInside")); + + // These should all fail compile if protoc is bad. + XCTAssertTrue([Other instancesRespondToSelector:@selector(hasA)]); + XCTAssertTrue([Other instancesRespondToSelector:@selector(setHasA:)]); + XCTAssertTrue([Other instancesRespondToSelector:@selector(a)]); + XCTAssertTrue([Other instancesRespondToSelector:@selector(setA:)]); + + // These the compiler should not generate. + XCTAssertFalse( + [Other instancesRespondToSelector:NSSelectorFromString(@"hasB")]); + XCTAssertFalse( + [Other instancesRespondToSelector:NSSelectorFromString(@"setHasB:")]); + XCTAssertFalse([Other instancesRespondToSelector:NSSelectorFromString(@"b")]); + XCTAssertFalse( + [Other instancesRespondToSelector:NSSelectorFromString(@"setB:")]); + + // This should fail if protoc filters it. + XCTAssertEqual(Other_FieldNumber_A, 1); + + // Make sure the definition at the top of the file is providing the value. + XCTAssertEqual(Other_FieldNumber_B, 0); +} + +@end diff --git a/objectivec/Tests/GPBMessageTests+Merge.m b/objectivec/Tests/GPBMessageTests+Merge.m new file mode 100644 index 00000000..599ad055 --- /dev/null +++ b/objectivec/Tests/GPBMessageTests+Merge.m @@ -0,0 +1,700 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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. + +#import "GPBTestUtilities.h" + +#import <objc/runtime.h> + +#import "GPBMessage.h" + +#import "google/protobuf/MapUnittest.pbobjc.h" +#import "google/protobuf/UnittestPreserveUnknownEnum.pbobjc.h" +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h" +#import "google/protobuf/UnittestRuntimeProto3.pbobjc.h" + +@interface MessageMergeTests : GPBTestCase +@end + +@implementation MessageMergeTests + +// TODO(thomasvl): Pull tests over from GPBMessageTests that are merge specific. + +- (void)testProto3MergingAndZeroValues { + // Proto2 covered in other tests. + + Message3 *src = [[Message3 alloc] init]; + Message3 *dst = [[Message3 alloc] init]; + NSData *testData1 = [@"abc" dataUsingEncoding:NSUTF8StringEncoding]; + NSData *testData2 = [@"def" dataUsingEncoding:NSUTF8StringEncoding]; + + dst.optionalInt32 = 1; + dst.optionalInt64 = 1; + dst.optionalUint32 = 1; + dst.optionalUint64 = 1; + dst.optionalSint32 = 1; + dst.optionalSint64 = 1; + dst.optionalFixed32 = 1; + dst.optionalFixed64 = 1; + dst.optionalSfixed32 = 1; + dst.optionalSfixed64 = 1; + dst.optionalFloat = 1.0f; + dst.optionalDouble = 1.0; + dst.optionalBool = YES; + dst.optionalString = @"bar"; + dst.optionalBytes = testData1; + dst.optionalEnum = Message3_Enum_Bar; + + // All zeros, nothing should overright. + + src.optionalInt32 = 0; + src.optionalInt64 = 0; + src.optionalUint32 = 0; + src.optionalUint64 = 0; + src.optionalSint32 = 0; + src.optionalSint64 = 0; + src.optionalFixed32 = 0; + src.optionalFixed64 = 0; + src.optionalSfixed32 = 0; + src.optionalSfixed64 = 0; + src.optionalFloat = 0.0f; + src.optionalDouble = 0.0; + src.optionalBool = NO; + src.optionalString = @""; + src.optionalBytes = [NSData data]; + src.optionalEnum = Message3_Enum_Foo; // first value + + [dst mergeFrom:src]; + + XCTAssertEqual(dst.optionalInt32, 1); + XCTAssertEqual(dst.optionalInt64, 1); + XCTAssertEqual(dst.optionalUint32, 1U); + XCTAssertEqual(dst.optionalUint64, 1U); + XCTAssertEqual(dst.optionalSint32, 1); + XCTAssertEqual(dst.optionalSint64, 1); + XCTAssertEqual(dst.optionalFixed32, 1U); + XCTAssertEqual(dst.optionalFixed64, 1U); + XCTAssertEqual(dst.optionalSfixed32, 1); + XCTAssertEqual(dst.optionalSfixed64, 1); + XCTAssertEqual(dst.optionalFloat, 1.0f); + XCTAssertEqual(dst.optionalDouble, 1.0); + XCTAssertEqual(dst.optionalBool, YES); + XCTAssertEqualObjects(dst.optionalString, @"bar"); + XCTAssertEqualObjects(dst.optionalBytes, testData1); + XCTAssertEqual(dst.optionalEnum, Message3_Enum_Bar); + + // Half the values that will replace. + + src.optionalInt32 = 0; + src.optionalInt64 = 2; + src.optionalUint32 = 0; + src.optionalUint64 = 2; + src.optionalSint32 = 0; + src.optionalSint64 = 2; + src.optionalFixed32 = 0; + src.optionalFixed64 = 2; + src.optionalSfixed32 = 0; + src.optionalSfixed64 = 2; + src.optionalFloat = 0.0f; + src.optionalDouble = 2.0; + src.optionalBool = YES; // No other value to use. :( + src.optionalString = @"baz"; + src.optionalBytes = nil; + src.optionalEnum = Message3_Enum_Baz; + + [dst mergeFrom:src]; + + XCTAssertEqual(dst.optionalInt32, 1); + XCTAssertEqual(dst.optionalInt64, 2); + XCTAssertEqual(dst.optionalUint32, 1U); + XCTAssertEqual(dst.optionalUint64, 2U); + XCTAssertEqual(dst.optionalSint32, 1); + XCTAssertEqual(dst.optionalSint64, 2); + XCTAssertEqual(dst.optionalFixed32, 1U); + XCTAssertEqual(dst.optionalFixed64, 2U); + XCTAssertEqual(dst.optionalSfixed32, 1); + XCTAssertEqual(dst.optionalSfixed64, 2); + XCTAssertEqual(dst.optionalFloat, 1.0f); + XCTAssertEqual(dst.optionalDouble, 2.0); + XCTAssertEqual(dst.optionalBool, YES); + XCTAssertEqualObjects(dst.optionalString, @"baz"); + XCTAssertEqualObjects(dst.optionalBytes, testData1); + XCTAssertEqual(dst.optionalEnum, Message3_Enum_Baz); + + // Other half the values that will replace. + + src.optionalInt32 = 3; + src.optionalInt64 = 0; + src.optionalUint32 = 3; + src.optionalUint64 = 0; + src.optionalSint32 = 3; + src.optionalSint64 = 0; + src.optionalFixed32 = 3; + src.optionalFixed64 = 0; + src.optionalSfixed32 = 3; + src.optionalSfixed64 = 0; + src.optionalFloat = 3.0f; + src.optionalDouble = 0.0; + src.optionalBool = YES; // No other value to use. :( + src.optionalString = nil; + src.optionalBytes = testData2; + src.optionalEnum = Message3_Enum_Foo; + + [dst mergeFrom:src]; + + XCTAssertEqual(dst.optionalInt32, 3); + XCTAssertEqual(dst.optionalInt64, 2); + XCTAssertEqual(dst.optionalUint32, 3U); + XCTAssertEqual(dst.optionalUint64, 2U); + XCTAssertEqual(dst.optionalSint32, 3); + XCTAssertEqual(dst.optionalSint64, 2); + XCTAssertEqual(dst.optionalFixed32, 3U); + XCTAssertEqual(dst.optionalFixed64, 2U); + XCTAssertEqual(dst.optionalSfixed32, 3); + XCTAssertEqual(dst.optionalSfixed64, 2); + XCTAssertEqual(dst.optionalFloat, 3.0f); + XCTAssertEqual(dst.optionalDouble, 2.0); + XCTAssertEqual(dst.optionalBool, YES); + XCTAssertEqualObjects(dst.optionalString, @"baz"); + XCTAssertEqualObjects(dst.optionalBytes, testData2); + XCTAssertEqual(dst.optionalEnum, Message3_Enum_Baz); + + [src release]; + [dst release]; +} + +- (void)testProto3MergingEnums { + UnknownEnumsMyMessage *src = [UnknownEnumsMyMessage message]; + UnknownEnumsMyMessage *dst = [UnknownEnumsMyMessage message]; + + // Known value. + + src.e = UnknownEnumsMyEnum_Bar; + src.repeatedEArray = + [GPBEnumArray arrayWithValidationFunction:UnknownEnumsMyEnum_IsValidValue + rawValue:UnknownEnumsMyEnum_Bar]; + src.repeatedPackedEArray = + [GPBEnumArray arrayWithValidationFunction:UnknownEnumsMyEnum_IsValidValue + rawValue:UnknownEnumsMyEnum_Bar]; + src.oneofE1 = UnknownEnumsMyEnum_Bar; + + [dst mergeFrom:src]; + + XCTAssertEqual(dst.e, UnknownEnumsMyEnum_Bar); + XCTAssertEqual(dst.repeatedEArray.count, 1U); + XCTAssertEqual([dst.repeatedEArray valueAtIndex:0], UnknownEnumsMyEnum_Bar); + XCTAssertEqual(dst.repeatedPackedEArray.count, 1U); + XCTAssertEqual([dst.repeatedPackedEArray valueAtIndex:0], + UnknownEnumsMyEnum_Bar); + XCTAssertEqual(dst.oneofE1, UnknownEnumsMyEnum_Bar); + + // Unknown value. + + const int32_t kUnknownValue = 666; + + SetUnknownEnumsMyMessage_E_RawValue(src, kUnknownValue); + src.repeatedEArray = + [GPBEnumArray arrayWithValidationFunction:UnknownEnumsMyEnum_IsValidValue + rawValue:kUnknownValue]; + src.repeatedPackedEArray = + [GPBEnumArray arrayWithValidationFunction:UnknownEnumsMyEnum_IsValidValue + rawValue:kUnknownValue]; + SetUnknownEnumsMyMessage_OneofE1_RawValue(src, kUnknownValue); + + [dst mergeFrom:src]; + + XCTAssertEqual(dst.e, UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue); + XCTAssertEqual(UnknownEnumsMyMessage_E_RawValue(dst), kUnknownValue); + XCTAssertEqual(dst.repeatedEArray.count, 2U); + XCTAssertEqual([dst.repeatedEArray valueAtIndex:0], UnknownEnumsMyEnum_Bar); + XCTAssertEqual([dst.repeatedEArray valueAtIndex:1], + UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue); + XCTAssertEqual([dst.repeatedEArray rawValueAtIndex:1], kUnknownValue); + XCTAssertEqual(dst.repeatedPackedEArray.count, 2U); + XCTAssertEqual([dst.repeatedPackedEArray valueAtIndex:0], + UnknownEnumsMyEnum_Bar); + XCTAssertEqual([dst.repeatedPackedEArray valueAtIndex:1], + UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue); + XCTAssertEqual([dst.repeatedPackedEArray rawValueAtIndex:1], kUnknownValue); + XCTAssertEqual(dst.oneofE1, + UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue); + XCTAssertEqual(UnknownEnumsMyMessage_OneofE1_RawValue(dst), kUnknownValue); +} + +- (void)testProto2MergeOneof { + Message2 *src = [Message2 message]; + Message2 *dst = [Message2 message]; + + // + // Make sure whatever is in dst gets cleared out be merging in something else. + // + + dst.oneofEnum = Message2_Enum_Bar; + +//%PDDM-DEFINE MERGE2_TEST(SET_NAME, SET_VALUE, CLEARED_NAME, CLEARED_DEFAULT) +//% src.oneof##SET_NAME = SET_VALUE; +//% [dst mergeFrom:src]; +//% XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_Oneof##SET_NAME); +//% XCTAssertEqual(dst.oneof##SET_NAME, SET_VALUE); +//% XCTAssertEqual(dst.oneof##CLEARED_NAME, CLEARED_DEFAULT); +//% +//%PDDM-EXPAND MERGE2_TEST(Int32, 10, Enum, Message2_Enum_Baz) +// This block of code is generated, do not edit it directly. + + src.oneofInt32 = 10; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofInt32); + XCTAssertEqual(dst.oneofInt32, 10); + XCTAssertEqual(dst.oneofEnum, Message2_Enum_Baz); + +//%PDDM-EXPAND MERGE2_TEST(Int64, 11, Int32, 100) +// This block of code is generated, do not edit it directly. + + src.oneofInt64 = 11; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofInt64); + XCTAssertEqual(dst.oneofInt64, 11); + XCTAssertEqual(dst.oneofInt32, 100); + +//%PDDM-EXPAND MERGE2_TEST(Uint32, 12U, Int64, 101) +// This block of code is generated, do not edit it directly. + + src.oneofUint32 = 12U; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofUint32); + XCTAssertEqual(dst.oneofUint32, 12U); + XCTAssertEqual(dst.oneofInt64, 101); + +//%PDDM-EXPAND MERGE2_TEST(Uint64, 13U, Uint32, 102U) +// This block of code is generated, do not edit it directly. + + src.oneofUint64 = 13U; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofUint64); + XCTAssertEqual(dst.oneofUint64, 13U); + XCTAssertEqual(dst.oneofUint32, 102U); + +//%PDDM-EXPAND MERGE2_TEST(Sint32, 14, Uint64, 103U) +// This block of code is generated, do not edit it directly. + + src.oneofSint32 = 14; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofSint32); + XCTAssertEqual(dst.oneofSint32, 14); + XCTAssertEqual(dst.oneofUint64, 103U); + +//%PDDM-EXPAND MERGE2_TEST(Sint64, 15, Sint32, 104) +// This block of code is generated, do not edit it directly. + + src.oneofSint64 = 15; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofSint64); + XCTAssertEqual(dst.oneofSint64, 15); + XCTAssertEqual(dst.oneofSint32, 104); + +//%PDDM-EXPAND MERGE2_TEST(Fixed32, 16U, Sint64, 105) +// This block of code is generated, do not edit it directly. + + src.oneofFixed32 = 16U; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofFixed32); + XCTAssertEqual(dst.oneofFixed32, 16U); + XCTAssertEqual(dst.oneofSint64, 105); + +//%PDDM-EXPAND MERGE2_TEST(Fixed64, 17U, Fixed32, 106U) +// This block of code is generated, do not edit it directly. + + src.oneofFixed64 = 17U; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofFixed64); + XCTAssertEqual(dst.oneofFixed64, 17U); + XCTAssertEqual(dst.oneofFixed32, 106U); + +//%PDDM-EXPAND MERGE2_TEST(Sfixed32, 18, Fixed64, 107U) +// This block of code is generated, do not edit it directly. + + src.oneofSfixed32 = 18; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofSfixed32); + XCTAssertEqual(dst.oneofSfixed32, 18); + XCTAssertEqual(dst.oneofFixed64, 107U); + +//%PDDM-EXPAND MERGE2_TEST(Sfixed64, 19, Sfixed32, 108) +// This block of code is generated, do not edit it directly. + + src.oneofSfixed64 = 19; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofSfixed64); + XCTAssertEqual(dst.oneofSfixed64, 19); + XCTAssertEqual(dst.oneofSfixed32, 108); + +//%PDDM-EXPAND MERGE2_TEST(Float, 20.0f, Sfixed64, 109) +// This block of code is generated, do not edit it directly. + + src.oneofFloat = 20.0f; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofFloat); + XCTAssertEqual(dst.oneofFloat, 20.0f); + XCTAssertEqual(dst.oneofSfixed64, 109); + +//%PDDM-EXPAND MERGE2_TEST(Double, 21.0, Float, 110.0f) +// This block of code is generated, do not edit it directly. + + src.oneofDouble = 21.0; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofDouble); + XCTAssertEqual(dst.oneofDouble, 21.0); + XCTAssertEqual(dst.oneofFloat, 110.0f); + +//%PDDM-EXPAND MERGE2_TEST(Bool, NO, Double, 111.0) +// This block of code is generated, do not edit it directly. + + src.oneofBool = NO; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofBool); + XCTAssertEqual(dst.oneofBool, NO); + XCTAssertEqual(dst.oneofDouble, 111.0); + +//%PDDM-EXPAND MERGE2_TEST(Enum, Message2_Enum_Bar, Bool, YES) +// This block of code is generated, do not edit it directly. + + src.oneofEnum = Message2_Enum_Bar; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofEnum); + XCTAssertEqual(dst.oneofEnum, Message2_Enum_Bar); + XCTAssertEqual(dst.oneofBool, YES); + +//%PDDM-EXPAND-END (14 expansions) + + NSString *oneofStringDefault = @"string"; + NSData *oneofBytesDefault = [@"data" dataUsingEncoding:NSUTF8StringEncoding]; + + src.oneofString = @"foo"; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofString); + XCTAssertEqualObjects(dst.oneofString, @"foo"); + XCTAssertEqual(dst.oneofEnum, Message2_Enum_Baz); + + src.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding]; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofBytes); + XCTAssertEqualObjects(dst.oneofBytes, + [@"bar" dataUsingEncoding:NSUTF8StringEncoding]); + XCTAssertEqualObjects(dst.oneofString, oneofStringDefault); + + Message2_OneofGroup *group = [Message2_OneofGroup message]; + group.a = 666; + src.oneofGroup = group; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofGroup); + Message2_OneofGroup *mergedGroup = [[dst.oneofGroup retain] autorelease]; + XCTAssertNotNil(mergedGroup); + XCTAssertNotEqual(mergedGroup, group); // Pointer comparision. + XCTAssertEqualObjects(mergedGroup, group); + XCTAssertEqualObjects(dst.oneofBytes, oneofBytesDefault); + + Message2 *subMessage = [Message2 message]; + subMessage.optionalInt32 = 777; + src.oneofMessage = subMessage; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofMessage); + Message2 *mergedSubMessage = [[dst.oneofMessage retain] autorelease]; + XCTAssertNotNil(mergedSubMessage); + XCTAssertNotEqual(mergedSubMessage, subMessage); // Pointer comparision. + XCTAssertEqualObjects(mergedSubMessage, subMessage); + XCTAssertNotNil(dst.oneofGroup); + XCTAssertNotEqual(dst.oneofGroup, mergedGroup); // Pointer comparision. + + // Back to something else ot make sure message clears out ok. + + src.oneofInt32 = 10; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofInt32); + XCTAssertNotNil(dst.oneofMessage); + XCTAssertNotEqual(dst.oneofMessage, + mergedSubMessage); // Pointer comparision. + + // + // Test merging in to message/group when they already had something. + // + + src.oneofGroup = group; + mergedGroup = [Message2_OneofGroup message]; + mergedGroup.b = 888; + dst.oneofGroup = mergedGroup; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofGroup); + // Shouldn't have been a new object. + XCTAssertEqual(dst.oneofGroup, mergedGroup); // Pointer comparision. + XCTAssertEqual(dst.oneofGroup.a, 666); // Pointer comparision. + XCTAssertEqual(dst.oneofGroup.b, 888); // Pointer comparision. + + src.oneofMessage = subMessage; + mergedSubMessage = [Message2 message]; + mergedSubMessage.optionalInt64 = 999; + dst.oneofMessage = mergedSubMessage; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofMessage); + // Shouldn't have been a new object. + XCTAssertEqual(dst.oneofMessage, mergedSubMessage); // Pointer comparision. + XCTAssertEqual(dst.oneofMessage.optionalInt32, 777); // Pointer comparision. + XCTAssertEqual(dst.oneofMessage.optionalInt64, 999); // Pointer comparision. +} + +- (void)testProto3MergeOneof { + Message3 *src = [Message3 message]; + Message3 *dst = [Message3 message]; + + // + // Make sure whatever is in dst gets cleared out be merging in something else. + // + + dst.oneofEnum = Message3_Enum_Bar; + +//%PDDM-DEFINE MERGE3_TEST(SET_NAME, SET_VALUE, CLEARED_NAME, CLEARED_DEFAULT) +//% src.oneof##SET_NAME = SET_VALUE; +//% [dst mergeFrom:src]; +//% XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_Oneof##SET_NAME); +//% XCTAssertEqual(dst.oneof##SET_NAME, SET_VALUE); +//% XCTAssertEqual(dst.oneof##CLEARED_NAME, CLEARED_DEFAULT); +//% +//%PDDM-EXPAND MERGE3_TEST(Int32, 10, Enum, Message3_Enum_Foo) +// This block of code is generated, do not edit it directly. + + src.oneofInt32 = 10; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofInt32); + XCTAssertEqual(dst.oneofInt32, 10); + XCTAssertEqual(dst.oneofEnum, Message3_Enum_Foo); + +//%PDDM-EXPAND MERGE3_TEST(Int64, 11, Int32, 0) +// This block of code is generated, do not edit it directly. + + src.oneofInt64 = 11; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofInt64); + XCTAssertEqual(dst.oneofInt64, 11); + XCTAssertEqual(dst.oneofInt32, 0); + +//%PDDM-EXPAND MERGE3_TEST(Uint32, 12U, Int64, 0) +// This block of code is generated, do not edit it directly. + + src.oneofUint32 = 12U; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofUint32); + XCTAssertEqual(dst.oneofUint32, 12U); + XCTAssertEqual(dst.oneofInt64, 0); + +//%PDDM-EXPAND MERGE3_TEST(Uint64, 13U, Uint32, 0U) +// This block of code is generated, do not edit it directly. + + src.oneofUint64 = 13U; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofUint64); + XCTAssertEqual(dst.oneofUint64, 13U); + XCTAssertEqual(dst.oneofUint32, 0U); + +//%PDDM-EXPAND MERGE3_TEST(Sint32, 14, Uint64, 0U) +// This block of code is generated, do not edit it directly. + + src.oneofSint32 = 14; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofSint32); + XCTAssertEqual(dst.oneofSint32, 14); + XCTAssertEqual(dst.oneofUint64, 0U); + +//%PDDM-EXPAND MERGE3_TEST(Sint64, 15, Sint32, 0) +// This block of code is generated, do not edit it directly. + + src.oneofSint64 = 15; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofSint64); + XCTAssertEqual(dst.oneofSint64, 15); + XCTAssertEqual(dst.oneofSint32, 0); + +//%PDDM-EXPAND MERGE3_TEST(Fixed32, 16U, Sint64, 0) +// This block of code is generated, do not edit it directly. + + src.oneofFixed32 = 16U; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofFixed32); + XCTAssertEqual(dst.oneofFixed32, 16U); + XCTAssertEqual(dst.oneofSint64, 0); + +//%PDDM-EXPAND MERGE3_TEST(Fixed64, 17U, Fixed32, 0U) +// This block of code is generated, do not edit it directly. + + src.oneofFixed64 = 17U; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofFixed64); + XCTAssertEqual(dst.oneofFixed64, 17U); + XCTAssertEqual(dst.oneofFixed32, 0U); + +//%PDDM-EXPAND MERGE3_TEST(Sfixed32, 18, Fixed64, 0U) +// This block of code is generated, do not edit it directly. + + src.oneofSfixed32 = 18; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofSfixed32); + XCTAssertEqual(dst.oneofSfixed32, 18); + XCTAssertEqual(dst.oneofFixed64, 0U); + +//%PDDM-EXPAND MERGE3_TEST(Sfixed64, 19, Sfixed32, 0) +// This block of code is generated, do not edit it directly. + + src.oneofSfixed64 = 19; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofSfixed64); + XCTAssertEqual(dst.oneofSfixed64, 19); + XCTAssertEqual(dst.oneofSfixed32, 0); + +//%PDDM-EXPAND MERGE3_TEST(Float, 20.0f, Sfixed64, 0) +// This block of code is generated, do not edit it directly. + + src.oneofFloat = 20.0f; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofFloat); + XCTAssertEqual(dst.oneofFloat, 20.0f); + XCTAssertEqual(dst.oneofSfixed64, 0); + +//%PDDM-EXPAND MERGE3_TEST(Double, 21.0, Float, 0.0f) +// This block of code is generated, do not edit it directly. + + src.oneofDouble = 21.0; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofDouble); + XCTAssertEqual(dst.oneofDouble, 21.0); + XCTAssertEqual(dst.oneofFloat, 0.0f); + +//%PDDM-EXPAND MERGE3_TEST(Bool, YES, Double, 0.0) +// This block of code is generated, do not edit it directly. + + src.oneofBool = YES; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofBool); + XCTAssertEqual(dst.oneofBool, YES); + XCTAssertEqual(dst.oneofDouble, 0.0); + +//%PDDM-EXPAND MERGE3_TEST(Enum, Message3_Enum_Bar, Bool, NO) +// This block of code is generated, do not edit it directly. + + src.oneofEnum = Message3_Enum_Bar; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofEnum); + XCTAssertEqual(dst.oneofEnum, Message3_Enum_Bar); + XCTAssertEqual(dst.oneofBool, NO); + +//%PDDM-EXPAND-END (14 expansions) + + NSString *oneofStringDefault = @""; + NSData *oneofBytesDefault = [NSData data]; + + src.oneofString = @"foo"; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofString); + XCTAssertEqualObjects(dst.oneofString, @"foo"); + XCTAssertEqual(dst.oneofEnum, Message3_Enum_Foo); + + src.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding]; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofBytes); + XCTAssertEqualObjects(dst.oneofBytes, + [@"bar" dataUsingEncoding:NSUTF8StringEncoding]); + XCTAssertEqualObjects(dst.oneofString, oneofStringDefault); + + + Message3 *subMessage = [Message3 message]; + subMessage.optionalInt32 = 777; + src.oneofMessage = subMessage; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofMessage); + Message3 *mergedSubMessage = [[dst.oneofMessage retain] autorelease]; + XCTAssertNotNil(mergedSubMessage); + XCTAssertNotEqual(mergedSubMessage, subMessage); // Pointer comparision. + XCTAssertEqualObjects(mergedSubMessage, subMessage); + XCTAssertEqualObjects(dst.oneofBytes, oneofBytesDefault); + + // Back to something else ot make sure message clears out ok. + + src.oneofInt32 = 10; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofInt32); + XCTAssertNotNil(dst.oneofMessage); + XCTAssertNotEqual(dst.oneofMessage, + mergedSubMessage); // Pointer comparision. + + // + // Test merging in to message when they already had something. + // + + src.oneofMessage = subMessage; + mergedSubMessage = [Message3 message]; + mergedSubMessage.optionalInt64 = 999; + dst.oneofMessage = mergedSubMessage; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofMessage); + // Shouldn't have been a new object. + XCTAssertEqual(dst.oneofMessage, mergedSubMessage); // Pointer comparision. + XCTAssertEqual(dst.oneofMessage.optionalInt32, 777); // Pointer comparision. + XCTAssertEqual(dst.oneofMessage.optionalInt64, 999); // Pointer comparision. +} + +#pragma mark - Subset from from map_tests.cc + +// TEST(GeneratedMapFieldTest, CopyFromMessageMap) +- (void)testMap_CopyFromMessageMap { + TestMessageMap *msg1 = [[TestMessageMap alloc] init]; + TestMessageMap *msg2 = [[TestMessageMap alloc] init]; + + TestAllTypes *subMsg = [TestAllTypes message]; + subMsg.repeatedInt32Array = [GPBInt32Array arrayWithValue:100]; + msg1.mapInt32Message = [GPBInt32ObjectDictionary dictionary]; + [msg1.mapInt32Message setValue:subMsg forKey:0]; + subMsg = nil; + + subMsg = [TestAllTypes message]; + subMsg.repeatedInt32Array = [GPBInt32Array arrayWithValue:101]; + msg2.mapInt32Message = [GPBInt32ObjectDictionary dictionary]; + [msg2.mapInt32Message setValue:subMsg forKey:0]; + subMsg = nil; + + [msg1 mergeFrom:msg2]; + + // Checks repeated field is overwritten. + XCTAssertEqual(msg1.mapInt32Message.count, 1U); + subMsg = [msg1.mapInt32Message valueForKey:0]; + XCTAssertNotNil(subMsg); + XCTAssertEqual(subMsg.repeatedInt32Array.count, 1U); + XCTAssertEqual([subMsg.repeatedInt32Array valueAtIndex:0], 101); + + [msg2 release]; + [msg1 release]; +} + +@end diff --git a/objectivec/Tests/GPBMessageTests+Runtime.m b/objectivec/Tests/GPBMessageTests+Runtime.m new file mode 100644 index 00000000..6ad29ca5 --- /dev/null +++ b/objectivec/Tests/GPBMessageTests+Runtime.m @@ -0,0 +1,1978 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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. + +#import "GPBTestUtilities.h" + +#import <objc/runtime.h> + +#import "GPBMessage.h" + +#import "google/protobuf/MapUnittest.pbobjc.h" +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h" +#import "google/protobuf/UnittestRuntimeProto3.pbobjc.h" + +@interface MessageRuntimeTests : GPBTestCase +@end + +@implementation MessageRuntimeTests + +// TODO(thomasvl): Pull tests over from GPBMessageTests that are runtime +// specific. + +- (void)testProto2HasMethodSupport { + NSArray *names = @[ + @"Int32", + @"Int64", + @"Uint32", + @"Uint64", + @"Sint32", + @"Sint64", + @"Fixed32", + @"Fixed64", + @"Sfixed32", + @"Sfixed64", + @"Float", + @"Double", + @"Bool", + @"String", + @"Bytes", + @"Group", + @"Message", + @"Enum", + ]; + + // Proto2 gets: + // - has* on all non repeated fields. + // - setHas* on all non repeated fields. + + for (NSString *name in names) { + // build the selector, i.e. - hasOptionalInt32/setHasOptionalInt32: + SEL hasSel = NSSelectorFromString( + [NSString stringWithFormat:@"hasOptional%@", name]); + SEL setHasSel = NSSelectorFromString( + [NSString stringWithFormat:@"setHasOptional%@:", name]); + XCTAssertTrue([Message2 instancesRespondToSelector:hasSel], @"field: %@", + name); + XCTAssertTrue([Message2 instancesRespondToSelector:setHasSel], @"field: %@", + name); + } + + // Repeated - no has/setHas + + for (NSString *name in names) { + // build the selector, i.e. - hasRepeatedInt32/setHasRepeatedInt32: + SEL hasSel = NSSelectorFromString( + [NSString stringWithFormat:@"hasRepeated%@", name]); + SEL setHasSel = NSSelectorFromString( + [NSString stringWithFormat:@"setHasRepeated%@:", name]); + XCTAssertFalse([Message2 instancesRespondToSelector:hasSel], @"field: %@", + name); + XCTAssertFalse([Message2 instancesRespondToSelector:setHasSel], + @"field: %@", name); + } + + // Oneofs - no has/setHas + + for (NSString *name in names) { + // build the selector, i.e. - hasOneofInt32/setHasOneofInt32: + SEL hasSel = + NSSelectorFromString([NSString stringWithFormat:@"hasOneof%@", name]); + SEL setHasSel = NSSelectorFromString( + [NSString stringWithFormat:@"setHasOneof%@:", name]); + XCTAssertFalse([Message2 instancesRespondToSelector:hasSel], @"field: %@", + name); + XCTAssertFalse([Message2 instancesRespondToSelector:setHasSel], + @"field: %@", name); + } +} + +- (void)testProto3HasMethodSupport { + NSArray *names = @[ + @"Int32", + @"Int64", + @"Uint32", + @"Uint64", + @"Sint32", + @"Sint64", + @"Fixed32", + @"Fixed64", + @"Sfixed32", + @"Sfixed64", + @"Float", + @"Double", + @"Bool", + @"String", + @"Bytes", + @"Message", + @"Enum", + ]; + + // Proto3 gets: + // - has* on non repeated message fields. + // - setHas* on all non repeated message fields. + + // Singlular + + for (NSString *name in names) { + // build the selector, i.e. - hasOptionalInt32/setHasOptionalInt32: + SEL hasSel = NSSelectorFromString( + [NSString stringWithFormat:@"hasOptional%@", name]); + SEL setHasSel = NSSelectorFromString( + [NSString stringWithFormat:@"setHasOptional%@:", name]); + if ([name isEqual:@"Group"] || [name isEqual:@"Message"]) { + // Sub messages/groups are the exception. + XCTAssertTrue([Message3 instancesRespondToSelector:hasSel], @"field: %@", + name); + XCTAssertTrue([Message3 instancesRespondToSelector:setHasSel], + @"field: %@", name); + } else { + XCTAssertFalse([Message3 instancesRespondToSelector:hasSel], @"field: %@", + name); + XCTAssertFalse([Message3 instancesRespondToSelector:setHasSel], + @"field: %@", name); + } + } + + // Repeated - no has/setHas + + for (NSString *name in names) { + // build the selector, i.e. - hasRepeatedInt32/setHasRepeatedInt32: + SEL hasSel = NSSelectorFromString( + [NSString stringWithFormat:@"hasRepeated%@", name]); + SEL setHasSel = NSSelectorFromString( + [NSString stringWithFormat:@"setHasRepeated%@:", name]); + XCTAssertFalse([Message3 instancesRespondToSelector:hasSel], @"field: %@", + name); + XCTAssertFalse([Message3 instancesRespondToSelector:setHasSel], + @"field: %@", name); + } + + // Oneofs - no has/setHas + + for (NSString *name in names) { + // build the selector, i.e. - hasOneofInt32/setHasOneofInt32: + SEL hasSel = + NSSelectorFromString([NSString stringWithFormat:@"hasOneof%@", name]); + SEL setHasSel = NSSelectorFromString( + [NSString stringWithFormat:@"setHasOneof%@:", name]); + XCTAssertFalse([Message2 instancesRespondToSelector:hasSel], @"field: %@", + name); + XCTAssertFalse([Message2 instancesRespondToSelector:setHasSel], + @"field: %@", name); + } +} + +- (void)testProto2SingleFieldHasBehavior { + // + // Setting to any value including the default value (0) should result has* + // being true. + // + +//%PDDM-DEFINE PROTO2_TEST_HAS_FIELD(FIELD, NON_ZERO_VALUE, ZERO_VALUE) +//% { // optional##FIELD :: NON_ZERO_VALUE +//% Message2 *msg = [[Message2 alloc] init]; +//% XCTAssertFalse(msg.hasOptional##FIELD); +//% XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_Optional##FIELD)); +//% msg.optional##FIELD = NON_ZERO_VALUE; +//% XCTAssertTrue(msg.hasOptional##FIELD); +//% XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_Optional##FIELD)); +//% [msg release]; +//% } +//% { // optional##FIELD :: ZERO_VALUE +//% Message2 *msg = [[Message2 alloc] init]; +//% XCTAssertFalse(msg.hasOptional##FIELD); +//% XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_Optional##FIELD)); +//% msg.optional##FIELD = ZERO_VALUE; +//% XCTAssertTrue(msg.hasOptional##FIELD); +//% XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_Optional##FIELD)); +//% [msg release]; +//% } +//% +//%PDDM-DEFINE PROTO2_TEST_HAS_FIELDS() +//%PROTO2_TEST_HAS_FIELD(Int32, 1, 0) +//%PROTO2_TEST_HAS_FIELD(Int64, 1, 0) +//%PROTO2_TEST_HAS_FIELD(Uint32, 1, 0) +//%PROTO2_TEST_HAS_FIELD(Uint64, 1, 0) +//%PROTO2_TEST_HAS_FIELD(Sint32, 1, 0) +//%PROTO2_TEST_HAS_FIELD(Sint64, 1, 0) +//%PROTO2_TEST_HAS_FIELD(Fixed32, 1, 0) +//%PROTO2_TEST_HAS_FIELD(Fixed64, 1, 0) +//%PROTO2_TEST_HAS_FIELD(Sfixed32, 1, 0) +//%PROTO2_TEST_HAS_FIELD(Sfixed64, 1, 0) +//%PROTO2_TEST_HAS_FIELD(Float, 1.0f, 0.0f) +//%PROTO2_TEST_HAS_FIELD(Double, 1.0, 0.0) +//%PROTO2_TEST_HAS_FIELD(Bool, YES, NO) +//%PROTO2_TEST_HAS_FIELD(String, @"foo", @"") +//%PROTO2_TEST_HAS_FIELD(Bytes, [@"foo" dataUsingEncoding:NSUTF8StringEncoding], [NSData data]) +//% // +//% // Test doesn't apply to optionalGroup/optionalMessage. +//% // +//% +//%PROTO2_TEST_HAS_FIELD(Enum, Message2_Enum_Bar, Message2_Enum_Foo) +//%PDDM-EXPAND PROTO2_TEST_HAS_FIELDS() +// This block of code is generated, do not edit it directly. + + { // optionalInt32 :: 1 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalInt32); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt32)); + msg.optionalInt32 = 1; + XCTAssertTrue(msg.hasOptionalInt32); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt32)); + [msg release]; + } + { // optionalInt32 :: 0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalInt32); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt32)); + msg.optionalInt32 = 0; + XCTAssertTrue(msg.hasOptionalInt32); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt32)); + [msg release]; + } + + { // optionalInt64 :: 1 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalInt64); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt64)); + msg.optionalInt64 = 1; + XCTAssertTrue(msg.hasOptionalInt64); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt64)); + [msg release]; + } + { // optionalInt64 :: 0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalInt64); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt64)); + msg.optionalInt64 = 0; + XCTAssertTrue(msg.hasOptionalInt64); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt64)); + [msg release]; + } + + { // optionalUint32 :: 1 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalUint32); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint32)); + msg.optionalUint32 = 1; + XCTAssertTrue(msg.hasOptionalUint32); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint32)); + [msg release]; + } + { // optionalUint32 :: 0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalUint32); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint32)); + msg.optionalUint32 = 0; + XCTAssertTrue(msg.hasOptionalUint32); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint32)); + [msg release]; + } + + { // optionalUint64 :: 1 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalUint64); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint64)); + msg.optionalUint64 = 1; + XCTAssertTrue(msg.hasOptionalUint64); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint64)); + [msg release]; + } + { // optionalUint64 :: 0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalUint64); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint64)); + msg.optionalUint64 = 0; + XCTAssertTrue(msg.hasOptionalUint64); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint64)); + [msg release]; + } + + { // optionalSint32 :: 1 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalSint32); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint32)); + msg.optionalSint32 = 1; + XCTAssertTrue(msg.hasOptionalSint32); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint32)); + [msg release]; + } + { // optionalSint32 :: 0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalSint32); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint32)); + msg.optionalSint32 = 0; + XCTAssertTrue(msg.hasOptionalSint32); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint32)); + [msg release]; + } + + { // optionalSint64 :: 1 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalSint64); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint64)); + msg.optionalSint64 = 1; + XCTAssertTrue(msg.hasOptionalSint64); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint64)); + [msg release]; + } + { // optionalSint64 :: 0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalSint64); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint64)); + msg.optionalSint64 = 0; + XCTAssertTrue(msg.hasOptionalSint64); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint64)); + [msg release]; + } + + { // optionalFixed32 :: 1 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalFixed32); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed32)); + msg.optionalFixed32 = 1; + XCTAssertTrue(msg.hasOptionalFixed32); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed32)); + [msg release]; + } + { // optionalFixed32 :: 0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalFixed32); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed32)); + msg.optionalFixed32 = 0; + XCTAssertTrue(msg.hasOptionalFixed32); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed32)); + [msg release]; + } + + { // optionalFixed64 :: 1 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalFixed64); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed64)); + msg.optionalFixed64 = 1; + XCTAssertTrue(msg.hasOptionalFixed64); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed64)); + [msg release]; + } + { // optionalFixed64 :: 0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalFixed64); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed64)); + msg.optionalFixed64 = 0; + XCTAssertTrue(msg.hasOptionalFixed64); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed64)); + [msg release]; + } + + { // optionalSfixed32 :: 1 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalSfixed32); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed32)); + msg.optionalSfixed32 = 1; + XCTAssertTrue(msg.hasOptionalSfixed32); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed32)); + [msg release]; + } + { // optionalSfixed32 :: 0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalSfixed32); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed32)); + msg.optionalSfixed32 = 0; + XCTAssertTrue(msg.hasOptionalSfixed32); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed32)); + [msg release]; + } + + { // optionalSfixed64 :: 1 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalSfixed64); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed64)); + msg.optionalSfixed64 = 1; + XCTAssertTrue(msg.hasOptionalSfixed64); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed64)); + [msg release]; + } + { // optionalSfixed64 :: 0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalSfixed64); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed64)); + msg.optionalSfixed64 = 0; + XCTAssertTrue(msg.hasOptionalSfixed64); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed64)); + [msg release]; + } + + { // optionalFloat :: 1.0f + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalFloat); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFloat)); + msg.optionalFloat = 1.0f; + XCTAssertTrue(msg.hasOptionalFloat); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFloat)); + [msg release]; + } + { // optionalFloat :: 0.0f + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalFloat); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFloat)); + msg.optionalFloat = 0.0f; + XCTAssertTrue(msg.hasOptionalFloat); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFloat)); + [msg release]; + } + + { // optionalDouble :: 1.0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalDouble); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalDouble)); + msg.optionalDouble = 1.0; + XCTAssertTrue(msg.hasOptionalDouble); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalDouble)); + [msg release]; + } + { // optionalDouble :: 0.0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalDouble); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalDouble)); + msg.optionalDouble = 0.0; + XCTAssertTrue(msg.hasOptionalDouble); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalDouble)); + [msg release]; + } + + { // optionalBool :: YES + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalBool); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBool)); + msg.optionalBool = YES; + XCTAssertTrue(msg.hasOptionalBool); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBool)); + [msg release]; + } + { // optionalBool :: NO + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalBool); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBool)); + msg.optionalBool = NO; + XCTAssertTrue(msg.hasOptionalBool); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBool)); + [msg release]; + } + + { // optionalString :: @"foo" + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalString); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalString)); + msg.optionalString = @"foo"; + XCTAssertTrue(msg.hasOptionalString); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalString)); + [msg release]; + } + { // optionalString :: @"" + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalString); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalString)); + msg.optionalString = @""; + XCTAssertTrue(msg.hasOptionalString); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalString)); + [msg release]; + } + + { // optionalBytes :: [@"foo" dataUsingEncoding:NSUTF8StringEncoding] + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalBytes); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBytes)); + msg.optionalBytes = [@"foo" dataUsingEncoding:NSUTF8StringEncoding]; + XCTAssertTrue(msg.hasOptionalBytes); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBytes)); + [msg release]; + } + { // optionalBytes :: [NSData data] + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalBytes); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBytes)); + msg.optionalBytes = [NSData data]; + XCTAssertTrue(msg.hasOptionalBytes); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBytes)); + [msg release]; + } + + // + // Test doesn't apply to optionalGroup/optionalMessage. + // + + { // optionalEnum :: Message2_Enum_Bar + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalEnum); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalEnum)); + msg.optionalEnum = Message2_Enum_Bar; + XCTAssertTrue(msg.hasOptionalEnum); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalEnum)); + [msg release]; + } + { // optionalEnum :: Message2_Enum_Foo + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalEnum); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalEnum)); + msg.optionalEnum = Message2_Enum_Foo; + XCTAssertTrue(msg.hasOptionalEnum); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalEnum)); + [msg release]; + } + +//%PDDM-EXPAND-END PROTO2_TEST_HAS_FIELDS() +} + +- (void)testProto3SingleFieldHasBehavior { + // + // Setting to any value including the default value (0) should result has* + // being true. + // + +//%PDDM-DEFINE PROTO3_TEST_HAS_FIELD(FIELD, NON_ZERO_VALUE, ZERO_VALUE) +//% { // optional##FIELD +//% Message3 *msg = [[Message3 alloc] init]; +//% XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_Optional##FIELD)); +//% msg.optional##FIELD = NON_ZERO_VALUE; +//% XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_Optional##FIELD)); +//% msg.optional##FIELD = ZERO_VALUE; +//% XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_Optional##FIELD)); +//% [msg release]; +//% } +//% +//%PDDM-DEFINE PROTO3_TEST_HAS_FIELDS() +//%PROTO3_TEST_HAS_FIELD(Int32, 1, 0) +//%PROTO3_TEST_HAS_FIELD(Int64, 1, 0) +//%PROTO3_TEST_HAS_FIELD(Uint32, 1, 0) +//%PROTO3_TEST_HAS_FIELD(Uint64, 1, 0) +//%PROTO3_TEST_HAS_FIELD(Sint32, 1, 0) +//%PROTO3_TEST_HAS_FIELD(Sint64, 1, 0) +//%PROTO3_TEST_HAS_FIELD(Fixed32, 1, 0) +//%PROTO3_TEST_HAS_FIELD(Fixed64, 1, 0) +//%PROTO3_TEST_HAS_FIELD(Sfixed32, 1, 0) +//%PROTO3_TEST_HAS_FIELD(Sfixed64, 1, 0) +//%PROTO3_TEST_HAS_FIELD(Float, 1.0f, 0.0f) +//%PROTO3_TEST_HAS_FIELD(Double, 1.0, 0.0) +//%PROTO3_TEST_HAS_FIELD(Bool, YES, NO) +//%PROTO3_TEST_HAS_FIELD(String, @"foo", @"") +//%PROTO3_TEST_HAS_FIELD(Bytes, [@"foo" dataUsingEncoding:NSUTF8StringEncoding], [NSData data]) +//% // +//% // Test doesn't apply to optionalGroup/optionalMessage. +//% // +//% +//%PROTO3_TEST_HAS_FIELD(Enum, Message3_Enum_Bar, Message3_Enum_Foo) +//%PDDM-EXPAND PROTO3_TEST_HAS_FIELDS() +// This block of code is generated, do not edit it directly. + + { // optionalInt32 + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalInt32)); + msg.optionalInt32 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalInt32)); + msg.optionalInt32 = 0; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalInt32)); + [msg release]; + } + + { // optionalInt64 + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalInt64)); + msg.optionalInt64 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalInt64)); + msg.optionalInt64 = 0; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalInt64)); + [msg release]; + } + + { // optionalUint32 + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalUint32)); + msg.optionalUint32 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalUint32)); + msg.optionalUint32 = 0; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalUint32)); + [msg release]; + } + + { // optionalUint64 + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalUint64)); + msg.optionalUint64 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalUint64)); + msg.optionalUint64 = 0; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalUint64)); + [msg release]; + } + + { // optionalSint32 + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSint32)); + msg.optionalSint32 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSint32)); + msg.optionalSint32 = 0; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSint32)); + [msg release]; + } + + { // optionalSint64 + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSint64)); + msg.optionalSint64 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSint64)); + msg.optionalSint64 = 0; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSint64)); + [msg release]; + } + + { // optionalFixed32 + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFixed32)); + msg.optionalFixed32 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFixed32)); + msg.optionalFixed32 = 0; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFixed32)); + [msg release]; + } + + { // optionalFixed64 + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFixed64)); + msg.optionalFixed64 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFixed64)); + msg.optionalFixed64 = 0; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFixed64)); + [msg release]; + } + + { // optionalSfixed32 + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSfixed32)); + msg.optionalSfixed32 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSfixed32)); + msg.optionalSfixed32 = 0; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSfixed32)); + [msg release]; + } + + { // optionalSfixed64 + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSfixed64)); + msg.optionalSfixed64 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSfixed64)); + msg.optionalSfixed64 = 0; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSfixed64)); + [msg release]; + } + + { // optionalFloat + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFloat)); + msg.optionalFloat = 1.0f; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFloat)); + msg.optionalFloat = 0.0f; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFloat)); + [msg release]; + } + + { // optionalDouble + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalDouble)); + msg.optionalDouble = 1.0; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalDouble)); + msg.optionalDouble = 0.0; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalDouble)); + [msg release]; + } + + { // optionalBool + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalBool)); + msg.optionalBool = YES; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalBool)); + msg.optionalBool = NO; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalBool)); + [msg release]; + } + + { // optionalString + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalString)); + msg.optionalString = @"foo"; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalString)); + msg.optionalString = @""; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalString)); + [msg release]; + } + + { // optionalBytes + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalBytes)); + msg.optionalBytes = [@"foo" dataUsingEncoding:NSUTF8StringEncoding]; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalBytes)); + msg.optionalBytes = [NSData data]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalBytes)); + [msg release]; + } + + // + // Test doesn't apply to optionalGroup/optionalMessage. + // + + { // optionalEnum + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalEnum)); + msg.optionalEnum = Message3_Enum_Bar; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalEnum)); + msg.optionalEnum = Message3_Enum_Foo; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalEnum)); + [msg release]; + } + +//%PDDM-EXPAND-END PROTO3_TEST_HAS_FIELDS() +} + +- (void)testAccessingProto2UnknownEnumValues { + Message2 *msg = [[Message2 alloc] init]; + + // Set it to something non zero, try and confirm it doesn't change. + + msg.optionalEnum = Message2_Enum_Bar; + XCTAssertThrowsSpecificNamed(msg.optionalEnum = 666, NSException, + NSInvalidArgumentException); + XCTAssertEqual(msg.optionalEnum, Message2_Enum_Bar); + + msg.oneofEnum = Message2_Enum_Bar; + XCTAssertThrowsSpecificNamed(msg.oneofEnum = 666, NSException, + NSInvalidArgumentException); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Bar); +} + +- (void)testAccessingProto3UnknownEnumValues { + Message3 *msg = [[Message3 alloc] init]; + + // Set it to something non zero, try and confirm it doesn't change. + + msg.optionalEnum = Message3_Enum_Bar; + XCTAssertThrowsSpecificNamed(msg.optionalEnum = 666, NSException, + NSInvalidArgumentException); + XCTAssertEqual(msg.optionalEnum, Message3_Enum_Bar); + + msg.oneofEnum = Message3_Enum_Bar; + XCTAssertThrowsSpecificNamed(msg.oneofEnum = 666, NSException, + NSInvalidArgumentException); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Bar); + + // Set via raw api to confirm it works. + + SetMessage3_OptionalEnum_RawValue(msg, 666); + XCTAssertEqual(msg.optionalEnum, + Message3_Enum_GPBUnrecognizedEnumeratorValue); + XCTAssertEqual(Message3_OptionalEnum_RawValue(msg), 666); + + SetMessage3_OneofEnum_RawValue(msg, 666); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_GPBUnrecognizedEnumeratorValue); + XCTAssertEqual(Message3_OneofEnum_RawValue(msg), 666); + + [msg release]; +} + +- (void)testProto2OneofBasicBehaviors { + Message2 *msg = [[Message2 alloc] init]; + + NSString *oneofStringDefault = @"string"; + NSData *oneofBytesDefault = [@"data" dataUsingEncoding:NSUTF8StringEncoding]; + + // Nothing set. + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_GPBUnsetOneOfCase); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + + // Set, check the case, check everyone has default but the one, confirm case + // didn't change. + + msg.oneofInt32 = 1; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofInt32); + XCTAssertEqual(msg.oneofInt32, 1); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofInt32); + + msg.oneofInt64 = 2; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofInt64); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 2); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofInt64); + + msg.oneofUint32 = 3; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofUint32); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 3U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofUint32); + + msg.oneofUint64 = 4; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofUint64); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 4U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofUint64); + + msg.oneofSint32 = 5; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSint32); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 5); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSint32); + + msg.oneofSint64 = 6; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSint64); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 6); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSint64); + + msg.oneofFixed32 = 7; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFixed32); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 7U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFixed32); + + msg.oneofFixed64 = 8; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFixed64); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 8U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFixed64); + + msg.oneofSfixed32 = 9; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSfixed32); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 9); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSfixed32); + + msg.oneofSfixed64 = 10; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSfixed64); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 10); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSfixed64); + + msg.oneofFloat = 11.0f; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFloat); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 11.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFloat); + + msg.oneofDouble = 12.0; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofDouble); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 12.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofDouble); + + msg.oneofBool = NO; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofBool); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofBool); + + msg.oneofString = @"foo"; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofString); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, @"foo"); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofString); + + msg.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofBytes); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, + [@"bar" dataUsingEncoding:NSUTF8StringEncoding]); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofBytes); + + Message2_OneofGroup *group = [Message2_OneofGroup message]; + msg.oneofGroup = group; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofGroup); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertEqual(msg.oneofGroup, group); // Pointer compare. + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofGroup); + + Message2 *subMessage = [Message2 message]; + msg.oneofMessage = subMessage; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofMessage); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotEqual(msg.oneofGroup, group); // Pointer compare. + XCTAssertEqual(msg.oneofMessage, subMessage); // Pointer compare. + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofMessage); + + msg.oneofEnum = Message2_Enum_Bar; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofEnum); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotEqual(msg.oneofGroup, group); // Pointer compare. + XCTAssertNotNil(msg.oneofMessage); + XCTAssertNotEqual(msg.oneofMessage, subMessage); // Pointer compare. + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Bar); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofEnum); + + // Test setting/calling clear clearing. + + [msg release]; + msg = [[Message2 alloc] init]; + + uint32_t values[] = { + Message2_O_OneOfCase_OneofInt32, + Message2_O_OneOfCase_OneofInt64, + Message2_O_OneOfCase_OneofUint32, + Message2_O_OneOfCase_OneofUint64, + Message2_O_OneOfCase_OneofSint32, + Message2_O_OneOfCase_OneofSint64, + Message2_O_OneOfCase_OneofFixed32, + Message2_O_OneOfCase_OneofFixed64, + Message2_O_OneOfCase_OneofSfixed32, + Message2_O_OneOfCase_OneofSfixed64, + Message2_O_OneOfCase_OneofFloat, + Message2_O_OneOfCase_OneofDouble, + Message2_O_OneOfCase_OneofBool, + Message2_O_OneOfCase_OneofString, + Message2_O_OneOfCase_OneofBytes, + Message2_O_OneOfCase_OneofGroup, + Message2_O_OneOfCase_OneofMessage, + Message2_O_OneOfCase_OneofEnum, + }; + + for (size_t i = 0; i < (sizeof(values) / sizeof((values[0]))); ++i) { + switch (values[i]) { + case Message2_O_OneOfCase_OneofInt32: + msg.oneofInt32 = 1; + break; + case Message2_O_OneOfCase_OneofInt64: + msg.oneofInt64 = 2; + break; + case Message2_O_OneOfCase_OneofUint32: + msg.oneofUint32 = 3; + break; + case Message2_O_OneOfCase_OneofUint64: + msg.oneofUint64 = 4; + break; + case Message2_O_OneOfCase_OneofSint32: + msg.oneofSint32 = 5; + break; + case Message2_O_OneOfCase_OneofSint64: + msg.oneofSint64 = 6; + break; + case Message2_O_OneOfCase_OneofFixed32: + msg.oneofFixed32 = 7; + break; + case Message2_O_OneOfCase_OneofFixed64: + msg.oneofFixed64 = 8; + break; + case Message2_O_OneOfCase_OneofSfixed32: + msg.oneofSfixed32 = 9; + break; + case Message2_O_OneOfCase_OneofSfixed64: + msg.oneofSfixed64 = 10; + break; + case Message2_O_OneOfCase_OneofFloat: + msg.oneofFloat = 11.0f; + break; + case Message2_O_OneOfCase_OneofDouble: + msg.oneofDouble = 12.0; + break; + case Message2_O_OneOfCase_OneofBool: + msg.oneofBool = YES; + break; + case Message2_O_OneOfCase_OneofString: + msg.oneofString = @"foo"; + break; + case Message2_O_OneOfCase_OneofBytes: + msg.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding]; + break; + case Message2_O_OneOfCase_OneofGroup: + msg.oneofGroup = group; + break; + case Message2_O_OneOfCase_OneofMessage: + msg.oneofMessage = subMessage; + break; + case Message2_O_OneOfCase_OneofEnum: + msg.oneofEnum = Message2_Enum_Bar; + break; + default: + XCTFail(@"shouldn't happen, loop: %zd", i); + break; + } + + XCTAssertEqual(msg.oOneOfCase, values[i], "Loop: %zd", i); + // No need to check the value was set, the above tests did that. + Message2_ClearOOneOfCase(msg); + // Nothing in the case. + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_GPBUnsetOneOfCase, + "Loop: %zd", i); + // Confirm everything is back to defaults after a clear. + XCTAssertEqual(msg.oneofInt32, 100, "Loop: %zd", i); + XCTAssertEqual(msg.oneofInt64, 101, "Loop: %zd", i); + XCTAssertEqual(msg.oneofUint32, 102U, "Loop: %zd", i); + XCTAssertEqual(msg.oneofUint64, 103U, "Loop: %zd", i); + XCTAssertEqual(msg.oneofSint32, 104, "Loop: %zd", i); + XCTAssertEqual(msg.oneofSint64, 105, "Loop: %zd", i); + XCTAssertEqual(msg.oneofFixed32, 106U, "Loop: %zd", i); + XCTAssertEqual(msg.oneofFixed64, 107U, "Loop: %zd", i); + XCTAssertEqual(msg.oneofSfixed32, 108, "Loop: %zd", i); + XCTAssertEqual(msg.oneofSfixed64, 109, "Loop: %zd", i); + XCTAssertEqual(msg.oneofFloat, 110.0f, "Loop: %zd", i); + XCTAssertEqual(msg.oneofDouble, 111.0, "Loop: %zd", i); + XCTAssertEqual(msg.oneofBool, YES, "Loop: %zd", i); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault, "Loop: %zd", i); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault, "Loop: %zd", i); + XCTAssertNotNil(msg.oneofGroup, "Loop: %zd", i); + XCTAssertNotEqual(msg.oneofGroup, group, "Loop: %zd", + i); // Pointer compare. + XCTAssertNotNil(msg.oneofMessage, "Loop: %zd", i); + XCTAssertNotEqual(msg.oneofMessage, subMessage, "Loop: %zd", + i); // Pointer compare. + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz, "Loop: %zd", i); + } + + [msg release]; +} + +- (void)testProto3OneofBasicBehaviors { + Message3 *msg = [[Message3 alloc] init]; + + NSString *oneofStringDefault = @""; + NSData *oneofBytesDefault = [NSData data]; + + // Nothing set. + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_GPBUnsetOneOfCase); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + + // Set, check the case, check everyone has default but the one, confirm case + // didn't change. + + msg.oneofInt32 = 1; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofInt32); + XCTAssertEqual(msg.oneofInt32, 1); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofInt32); + + msg.oneofInt64 = 2; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofInt64); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 2); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofInt64); + + msg.oneofUint32 = 3; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofUint32); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 3U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofUint32); + + msg.oneofUint64 = 4; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofUint64); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 4U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofUint64); + + msg.oneofSint32 = 5; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSint32); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 5); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSint32); + + msg.oneofSint64 = 6; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSint64); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 6); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSint64); + + msg.oneofFixed32 = 7; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFixed32); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 7U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFixed32); + + msg.oneofFixed64 = 8; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFixed64); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 8U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFixed64); + + msg.oneofSfixed32 = 9; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSfixed32); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 9); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSfixed32); + + msg.oneofSfixed64 = 10; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSfixed64); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 10); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSfixed64); + + msg.oneofFloat = 11.0f; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFloat); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 11.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFloat); + + msg.oneofDouble = 12.0; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofDouble); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 12.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofDouble); + + msg.oneofBool = YES; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofBool); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofBool); + + msg.oneofString = @"foo"; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofString); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, @"foo"); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofString); + + msg.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofBytes); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, + [@"bar" dataUsingEncoding:NSUTF8StringEncoding]); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofBytes); + + Message3 *subMessage = [Message3 message]; + msg.oneofMessage = subMessage; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofMessage); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertEqual(msg.oneofMessage, subMessage); // Pointer compare. + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofMessage); + + msg.oneofEnum = Message3_Enum_Bar; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofEnum); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertNotEqual(msg.oneofMessage, subMessage); // Pointer compare. + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Bar); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofEnum); + + // Test setting/calling clear clearing. + + [msg release]; + msg = [[Message3 alloc] init]; + + uint32_t values[] = { + Message3_O_OneOfCase_OneofInt32, + Message3_O_OneOfCase_OneofInt64, + Message3_O_OneOfCase_OneofUint32, + Message3_O_OneOfCase_OneofUint64, + Message3_O_OneOfCase_OneofSint32, + Message3_O_OneOfCase_OneofSint64, + Message3_O_OneOfCase_OneofFixed32, + Message3_O_OneOfCase_OneofFixed64, + Message3_O_OneOfCase_OneofSfixed32, + Message3_O_OneOfCase_OneofSfixed64, + Message3_O_OneOfCase_OneofFloat, + Message3_O_OneOfCase_OneofDouble, + Message3_O_OneOfCase_OneofBool, + Message3_O_OneOfCase_OneofString, + Message3_O_OneOfCase_OneofBytes, + Message3_O_OneOfCase_OneofMessage, + Message3_O_OneOfCase_OneofEnum, + }; + + for (size_t i = 0; i < (sizeof(values) / sizeof((values[0]))); ++i) { + switch (values[i]) { + case Message3_O_OneOfCase_OneofInt32: + msg.oneofInt32 = 1; + break; + case Message3_O_OneOfCase_OneofInt64: + msg.oneofInt64 = 2; + break; + case Message3_O_OneOfCase_OneofUint32: + msg.oneofUint32 = 3; + break; + case Message3_O_OneOfCase_OneofUint64: + msg.oneofUint64 = 4; + break; + case Message3_O_OneOfCase_OneofSint32: + msg.oneofSint32 = 5; + break; + case Message3_O_OneOfCase_OneofSint64: + msg.oneofSint64 = 6; + break; + case Message3_O_OneOfCase_OneofFixed32: + msg.oneofFixed32 = 7; + break; + case Message3_O_OneOfCase_OneofFixed64: + msg.oneofFixed64 = 8; + break; + case Message3_O_OneOfCase_OneofSfixed32: + msg.oneofSfixed32 = 9; + break; + case Message3_O_OneOfCase_OneofSfixed64: + msg.oneofSfixed64 = 10; + break; + case Message3_O_OneOfCase_OneofFloat: + msg.oneofFloat = 11.0f; + break; + case Message3_O_OneOfCase_OneofDouble: + msg.oneofDouble = 12.0; + break; + case Message3_O_OneOfCase_OneofBool: + msg.oneofBool = YES; + break; + case Message3_O_OneOfCase_OneofString: + msg.oneofString = @"foo"; + break; + case Message3_O_OneOfCase_OneofBytes: + msg.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding]; + break; + case Message3_O_OneOfCase_OneofMessage: + msg.oneofMessage = subMessage; + break; + case Message3_O_OneOfCase_OneofEnum: + msg.oneofEnum = Message3_Enum_Baz; + break; + default: + XCTFail(@"shouldn't happen, loop: %zd", i); + break; + } + + XCTAssertEqual(msg.oOneOfCase, values[i], "Loop: %zd", i); + // No need to check the value was set, the above tests did that. + Message3_ClearOOneOfCase(msg); + // Nothing in the case. + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_GPBUnsetOneOfCase, + "Loop: %zd", i); + // Confirm everything is back to defaults after a clear. + XCTAssertEqual(msg.oneofInt32, 0, "Loop: %zd", i); + XCTAssertEqual(msg.oneofInt64, 0, "Loop: %zd", i); + XCTAssertEqual(msg.oneofUint32, 0U, "Loop: %zd", i); + XCTAssertEqual(msg.oneofUint64, 0U, "Loop: %zd", i); + XCTAssertEqual(msg.oneofSint32, 0, "Loop: %zd", i); + XCTAssertEqual(msg.oneofSint64, 0, "Loop: %zd", i); + XCTAssertEqual(msg.oneofFixed32, 0U, "Loop: %zd", i); + XCTAssertEqual(msg.oneofFixed64, 0U, "Loop: %zd", i); + XCTAssertEqual(msg.oneofSfixed32, 0, "Loop: %zd", i); + XCTAssertEqual(msg.oneofSfixed64, 0, "Loop: %zd", i); + XCTAssertEqual(msg.oneofFloat, 0.0f, "Loop: %zd", i); + XCTAssertEqual(msg.oneofDouble, 0.0, "Loop: %zd", i); + XCTAssertEqual(msg.oneofBool, NO, "Loop: %zd", i); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault, "Loop: %zd", i); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault, "Loop: %zd", i); + XCTAssertNotNil(msg.oneofMessage, "Loop: %zd", i); + XCTAssertNotEqual(msg.oneofMessage, subMessage, "Loop: %zd", + i); // Pointer compare. + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo, "Loop: %zd", i); + } + + [msg release]; +} + +- (void)testCopyingMakesUniqueObjects { + const int repeatCount = 5; + TestAllTypes *msg1 = [TestAllTypes message]; + [self setAllFields:msg1 repeatedCount:repeatCount]; + + TestAllTypes *msg2 = [[msg1 copy] autorelease]; + + XCTAssertNotEqual(msg1, msg2); // Ptr compare, new object. + XCTAssertEqualObjects(msg1, msg2); // Equal values. + + // Pointer comparisions, different objects. + + XCTAssertNotEqual(msg1.optionalGroup, msg2.optionalGroup); + XCTAssertNotEqual(msg1.optionalNestedMessage, msg2.optionalNestedMessage); + XCTAssertNotEqual(msg1.optionalForeignMessage, msg2.optionalForeignMessage); + XCTAssertNotEqual(msg1.optionalImportMessage, msg2.optionalImportMessage); + + XCTAssertNotEqual(msg1.repeatedInt32Array, msg2.repeatedInt32Array); + XCTAssertNotEqual(msg1.repeatedInt64Array, msg2.repeatedInt64Array); + XCTAssertNotEqual(msg1.repeatedUint32Array, msg2.repeatedUint32Array); + XCTAssertNotEqual(msg1.repeatedUint64Array, msg2.repeatedUint64Array); + XCTAssertNotEqual(msg1.repeatedSint32Array, msg2.repeatedSint32Array); + XCTAssertNotEqual(msg1.repeatedSint64Array, msg2.repeatedSint64Array); + XCTAssertNotEqual(msg1.repeatedFixed32Array, msg2.repeatedFixed32Array); + XCTAssertNotEqual(msg1.repeatedFixed64Array, msg2.repeatedFixed64Array); + XCTAssertNotEqual(msg1.repeatedSfixed32Array, msg2.repeatedSfixed32Array); + XCTAssertNotEqual(msg1.repeatedSfixed64Array, msg2.repeatedSfixed64Array); + XCTAssertNotEqual(msg1.repeatedFloatArray, msg2.repeatedFloatArray); + XCTAssertNotEqual(msg1.repeatedDoubleArray, msg2.repeatedDoubleArray); + XCTAssertNotEqual(msg1.repeatedBoolArray, msg2.repeatedBoolArray); + XCTAssertNotEqual(msg1.repeatedStringArray, msg2.repeatedStringArray); + XCTAssertNotEqual(msg1.repeatedBytesArray, msg2.repeatedBytesArray); + XCTAssertNotEqual(msg1.repeatedGroupArray, msg2.repeatedGroupArray); + XCTAssertNotEqual(msg1.repeatedNestedMessageArray, + msg2.repeatedNestedMessageArray); + XCTAssertNotEqual(msg1.repeatedForeignMessageArray, + msg2.repeatedForeignMessageArray); + XCTAssertNotEqual(msg1.repeatedImportMessageArray, + msg2.repeatedImportMessageArray); + XCTAssertNotEqual(msg1.repeatedNestedEnumArray, msg2.repeatedNestedEnumArray); + XCTAssertNotEqual(msg1.repeatedForeignEnumArray, + msg2.repeatedForeignEnumArray); + XCTAssertNotEqual(msg1.repeatedImportEnumArray, msg2.repeatedImportEnumArray); + XCTAssertNotEqual(msg1.repeatedStringPieceArray, + msg2.repeatedStringPieceArray); + XCTAssertNotEqual(msg1.repeatedCordArray, msg2.repeatedCordArray); + + for (int i = 0; i < repeatCount; i++) { + XCTAssertNotEqual(msg1.repeatedNestedMessageArray[i], + msg2.repeatedNestedMessageArray[i]); + XCTAssertNotEqual(msg1.repeatedForeignMessageArray[i], + msg2.repeatedForeignMessageArray[i]); + XCTAssertNotEqual(msg1.repeatedImportMessageArray[i], + msg2.repeatedImportMessageArray[i]); + } +} + +- (void)testCopyingMapsMakesUniqueObjects { + TestMap *msg1 = [TestMap message]; + [self setAllMapFields:msg1 numEntries:5]; + + TestMap *msg2 = [[msg1 copy] autorelease]; + + XCTAssertNotEqual(msg1, msg2); // Ptr compare, new object. + XCTAssertEqualObjects(msg1, msg2); // Equal values. + + // Pointer comparisions, different objects. + XCTAssertNotEqual(msg1.mapInt32Int32, msg2.mapInt32Int32); + XCTAssertNotEqual(msg1.mapInt64Int64, msg2.mapInt64Int64); + XCTAssertNotEqual(msg1.mapUint32Uint32, msg2.mapUint32Uint32); + XCTAssertNotEqual(msg1.mapUint64Uint64, msg2.mapUint64Uint64); + XCTAssertNotEqual(msg1.mapSint32Sint32, msg2.mapSint32Sint32); + XCTAssertNotEqual(msg1.mapSint64Sint64, msg2.mapSint64Sint64); + XCTAssertNotEqual(msg1.mapFixed32Fixed32, msg2.mapFixed32Fixed32); + XCTAssertNotEqual(msg1.mapFixed64Fixed64, msg2.mapFixed64Fixed64); + XCTAssertNotEqual(msg1.mapSfixed32Sfixed32, msg2.mapSfixed32Sfixed32); + XCTAssertNotEqual(msg1.mapSfixed64Sfixed64, msg2.mapSfixed64Sfixed64); + XCTAssertNotEqual(msg1.mapInt32Float, msg2.mapInt32Float); + XCTAssertNotEqual(msg1.mapInt32Double, msg2.mapInt32Double); + XCTAssertNotEqual(msg1.mapBoolBool, msg2.mapBoolBool); + XCTAssertNotEqual(msg1.mapStringString, msg2.mapStringString); + XCTAssertNotEqual(msg1.mapInt32Bytes, msg2.mapInt32Bytes); + XCTAssertNotEqual(msg1.mapInt32Enum, msg2.mapInt32Enum); + XCTAssertNotEqual(msg1.mapInt32ForeignMessage, msg2.mapInt32ForeignMessage); + + // Ensure the messages are unique per map. + [msg1.mapInt32ForeignMessage + enumerateKeysAndValuesUsingBlock:^(int32_t key, id value, BOOL *stop) { +#pragma unused(stop) + ForeignMessage *subMsg2 = [msg2.mapInt32ForeignMessage valueForKey:key]; + XCTAssertNotEqual(value, subMsg2); // Ptr compare, new object. + }]; +} + +#pragma mark - Subset from from map_tests.cc + +// TEST(GeneratedMapFieldTest, IsInitialized) +- (void)testMap_IsInitialized { + TestRequiredMessageMap *msg = [[TestRequiredMessageMap alloc] init]; + + // Add an uninitialized message. + TestRequired *subMsg = [[TestRequired alloc] init]; + msg.mapField = [GPBInt32ObjectDictionary dictionary]; + [msg.mapField setValue:subMsg forKey:0]; + XCTAssertFalse(msg.initialized); + + // Initialize uninitialized message + subMsg.a = 0; + subMsg.b = 0; + subMsg.c = 0; + XCTAssertTrue(msg.initialized); + + [subMsg release]; + [msg release]; +} + +@end diff --git a/objectivec/Tests/GPBMessageTests+Serialization.m b/objectivec/Tests/GPBMessageTests+Serialization.m new file mode 100644 index 00000000..ddc2ae19 --- /dev/null +++ b/objectivec/Tests/GPBMessageTests+Serialization.m @@ -0,0 +1,838 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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. + +#import "GPBTestUtilities.h" + +#import <objc/runtime.h> + +#import "GPBMessage.h" + +#import "google/protobuf/MapProto2Unittest.pbobjc.h" +#import "google/protobuf/MapUnittest.pbobjc.h" +#import "google/protobuf/UnittestDropUnknownFields.pbobjc.h" +#import "google/protobuf/UnittestPreserveUnknownEnum.pbobjc.h" +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h" +#import "google/protobuf/UnittestRuntimeProto3.pbobjc.h" + +#ifndef GPBARRAYSIZE +#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0])))) +#endif // GPBARRAYSIZE + +static NSData *DataFromCStr(const char *str) { + return [NSData dataWithBytes:str length:strlen(str)]; +} + +@interface MessageSerializationTests : GPBTestCase +@end + +@implementation MessageSerializationTests + +// TODO(thomasvl): Pull tests over from GPBMessageTests that are serialization +// specific. + +- (void)testProto3SerializationHandlingDefaults { + // Proto2 covered in other tests. + + Message3 *msg = [[Message3 alloc] init]; + + // Add defaults, no output. + + NSData *data = [msg data]; + XCTAssertEqual([data length], 0U); + + // All zeros, still nothing. + + msg.optionalInt32 = 0; + msg.optionalInt64 = 0; + msg.optionalUint32 = 0; + msg.optionalUint64 = 0; + msg.optionalSint32 = 0; + msg.optionalSint64 = 0; + msg.optionalFixed32 = 0; + msg.optionalFixed64 = 0; + msg.optionalSfixed32 = 0; + msg.optionalSfixed64 = 0; + msg.optionalFloat = 0.0f; + msg.optionalDouble = 0.0; + msg.optionalBool = NO; + msg.optionalString = @""; + msg.optionalBytes = [NSData data]; + msg.optionalEnum = Message3_Enum_Foo; // first value + + data = [msg data]; + XCTAssertEqual([data length], 0U); + + // The two that also take nil as nothing. + + msg.optionalString = nil; + msg.optionalBytes = nil; + + data = [msg data]; + XCTAssertEqual([data length], 0U); + + // Set one field... + + msg.optionalInt32 = 1; + + data = [msg data]; + const uint8_t expectedBytes[] = {0x08, 0x01}; + NSData *expected = [NSData dataWithBytes:expectedBytes length:2]; + XCTAssertEqualObjects(data, expected); + + // Back to zero... + + msg.optionalInt32 = 0; + + data = [msg data]; + XCTAssertEqual([data length], 0U); + + [msg release]; +} + +- (void)testProto3DroppingUnknownFields { + DropUnknownsFooWithExtraFields *fooWithExtras = + [[DropUnknownsFooWithExtraFields alloc] init]; + + fooWithExtras.int32Value = 1; + fooWithExtras.enumValue = DropUnknownsFooWithExtraFields_NestedEnum_Baz; + fooWithExtras.extraInt32Value = 2; + + DropUnknownsFoo *foo = [DropUnknownsFoo parseFromData:[fooWithExtras data]]; + + XCTAssertEqual(foo.int32Value, 1); + XCTAssertEqual(foo.enumValue, DropUnknownsFoo_NestedEnum_Baz); + // Nothing should end up in the unknowns. + XCTAssertEqual([foo.unknownFields countOfFields], 0U); + + [fooWithExtras release]; + fooWithExtras = [DropUnknownsFooWithExtraFields parseFromData:[foo data]]; + XCTAssertEqual(fooWithExtras.int32Value, 1); + XCTAssertEqual(fooWithExtras.enumValue, + DropUnknownsFooWithExtraFields_NestedEnum_Baz); + // And the extra value is gone (back to the default). + XCTAssertEqual(fooWithExtras.extraInt32Value, 0); + XCTAssertEqual([foo.unknownFields countOfFields], 0U); +} + +- (void)testProto2UnknownEnumToUnknownField { + Message3 *orig = [[Message3 alloc] init]; + + orig.optionalEnum = Message3_Enum_Extra3; + orig.repeatedEnumArray = + [GPBEnumArray arrayWithValidationFunction:Message3_Enum_IsValidValue + rawValue:Message3_Enum_Extra3]; + orig.repeatedPackedEnumArray = + [GPBEnumArray arrayWithValidationFunction:Message3_Enum_IsValidValue + rawValue:Message3_Enum_Extra3]; + orig.oneofEnum = Message3_Enum_Extra3; + + Message2 *msg = [[Message2 alloc] initWithData:[orig data]]; + + // None of the fields should be set. + + XCTAssertFalse(msg.hasOptionalEnum); + XCTAssertEqual(msg.repeatedEnumArray.count, 0U); + XCTAssertEqual(msg.repeatedPackedEnumArray.count, 0U); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_GPBUnsetOneOfCase); + + // All the values should be in unknown fields. + + GPBUnknownFieldSet *unknownFields = msg.unknownFields; + + XCTAssertEqual([unknownFields countOfFields], 4U); + XCTAssertTrue([unknownFields hasField:Message2_FieldNumber_OptionalEnum]); + XCTAssertTrue( + [unknownFields hasField:Message2_FieldNumber_RepeatedEnumArray]); + XCTAssertTrue( + [unknownFields hasField:Message2_FieldNumber_RepeatedPackedEnumArray]); + XCTAssertTrue([unknownFields hasField:Message2_FieldNumber_OneofEnum]); + + GPBField *field = [unknownFields getField:Message2_FieldNumber_OptionalEnum]; + XCTAssertEqual(field.varintList.count, 1U); + XCTAssertEqual([field.varintList valueAtIndex:0], + (uint64_t)Message3_Enum_Extra3); + + field = [unknownFields getField:Message2_FieldNumber_RepeatedEnumArray]; + XCTAssertEqual(field.varintList.count, 1U); + XCTAssertEqual([field.varintList valueAtIndex:0], + (uint64_t)Message3_Enum_Extra3); + + field = [unknownFields getField:Message2_FieldNumber_RepeatedPackedEnumArray]; + XCTAssertEqual(field.varintList.count, 1U); + XCTAssertEqual([field.varintList valueAtIndex:0], + (uint64_t)Message3_Enum_Extra3); + + field = [unknownFields getField:Message2_FieldNumber_OneofEnum]; + XCTAssertEqual(field.varintList.count, 1U); + XCTAssertEqual([field.varintList valueAtIndex:0], + (uint64_t)Message3_Enum_Extra3); + + [msg release]; + [orig release]; +} + +- (void)testProto3UnknownEnumPreserving { + UnknownEnumsMyMessagePlusExtra *orig = + [UnknownEnumsMyMessagePlusExtra message]; + + orig.e = UnknownEnumsMyEnumPlusExtra_EExtra; + orig.repeatedEArray = [GPBEnumArray + arrayWithValidationFunction:UnknownEnumsMyEnumPlusExtra_IsValidValue + rawValue:UnknownEnumsMyEnumPlusExtra_EExtra]; + orig.repeatedPackedEArray = [GPBEnumArray + arrayWithValidationFunction:UnknownEnumsMyEnumPlusExtra_IsValidValue + rawValue:UnknownEnumsMyEnumPlusExtra_EExtra]; + orig.oneofE1 = UnknownEnumsMyEnumPlusExtra_EExtra; + + // Everything should be there via raw values. + + UnknownEnumsMyMessage *msg = + [UnknownEnumsMyMessage parseFromData:[orig data]]; + + XCTAssertEqual(msg.e, UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue); + XCTAssertEqual(UnknownEnumsMyMessage_E_RawValue(msg), + UnknownEnumsMyEnumPlusExtra_EExtra); + XCTAssertEqual(msg.repeatedEArray.count, 1U); + XCTAssertEqual([msg.repeatedEArray valueAtIndex:0], + UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue); + XCTAssertEqual([msg.repeatedEArray rawValueAtIndex:0], + (UnknownEnumsMyEnum)UnknownEnumsMyEnumPlusExtra_EExtra); + XCTAssertEqual(msg.repeatedPackedEArray.count, 1U); + XCTAssertEqual([msg.repeatedPackedEArray valueAtIndex:0], + UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue); + XCTAssertEqual([msg.repeatedPackedEArray rawValueAtIndex:0], + (UnknownEnumsMyEnum)UnknownEnumsMyEnumPlusExtra_EExtra); + XCTAssertEqual(msg.oneofE1, + UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue); + XCTAssertEqual(UnknownEnumsMyMessage_OneofE1_RawValue(msg), + UnknownEnumsMyEnumPlusExtra_EExtra); + + // Everything should go out and come back. + + orig = [UnknownEnumsMyMessagePlusExtra parseFromData:[msg data]]; + + XCTAssertEqual(orig.e, UnknownEnumsMyEnumPlusExtra_EExtra); + XCTAssertEqual(orig.repeatedEArray.count, 1U); + XCTAssertEqual([orig.repeatedEArray valueAtIndex:0], + UnknownEnumsMyEnumPlusExtra_EExtra); + XCTAssertEqual(orig.repeatedPackedEArray.count, 1U); + XCTAssertEqual([orig.repeatedPackedEArray valueAtIndex:0], + UnknownEnumsMyEnumPlusExtra_EExtra); + XCTAssertEqual(orig.oneofE1, UnknownEnumsMyEnumPlusExtra_EExtra); +} + +//%PDDM-DEFINE TEST_ROUNDTRIP_ONEOF(MESSAGE, FIELD, VALUE) +//%TEST_ROUNDTRIP_ONEOF_ADV(MESSAGE, FIELD, VALUE, ) +//%PDDM-DEFINE TEST_ROUNDTRIP_ONEOF_ADV(MESSAGE, FIELD, VALUE, EQ_SUFFIX) +//% { // oneof##FIELD +//% MESSAGE *orig = [[MESSAGE alloc] init]; +//% orig.oneof##FIELD = VALUE; +//% XCTAssertEqual(orig.oOneOfCase, MESSAGE##_O_OneOfCase_Oneof##FIELD); +//% MESSAGE *msg = [MESSAGE parseFromData:[orig data]]; +//% XCTAssertEqual(msg.oOneOfCase, MESSAGE##_O_OneOfCase_Oneof##FIELD); +//% XCTAssertEqual##EQ_SUFFIX(msg.oneof##FIELD, VALUE); +//% [orig release]; +//% } +//% +//%PDDM-DEFINE TEST_ROUNDTRIP_ONEOFS(SYNTAX, BOOL_NON_DEFAULT) +//%- (void)testProto##SYNTAX##RoundTripOneof { +//% +//%GROUP_INIT##SYNTAX() Message##SYNTAX *subMessage = [[Message##SYNTAX alloc] init]; +//% XCTAssertNotNil(subMessage); +//% subMessage.optionalInt32 = 666; +//% +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Int32, 1) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Int64, 2) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Uint32, 3U) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Uint64, 4U) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Sint32, 5) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Sint64, 6) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Fixed32, 7U) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Fixed64, 8U) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Sfixed32, 9) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Sfixed64, 10) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Float, 11.0f) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Double, 12.0) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Bool, BOOL_NON_DEFAULT) +//%TEST_ROUNDTRIP_ONEOF_ADV(Message##SYNTAX, String, @"foo", Objects) +//%TEST_ROUNDTRIP_ONEOF_ADV(Message##SYNTAX, Bytes, [@"bar" dataUsingEncoding:NSUTF8StringEncoding], Objects) +//%GROUP_TEST##SYNTAX()TEST_ROUNDTRIP_ONEOF_ADV(Message##SYNTAX, Message, subMessage, Objects) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Enum, Message2_Enum_Bar) +//%GROUP_CLEANUP##SYNTAX() [subMessage release]; +//%} +//% +//%PDDM-DEFINE GROUP_INIT2() +//% Message2_OneofGroup *group = [[Message2_OneofGroup alloc] init]; +//% XCTAssertNotNil(group); +//% group.a = 777; +//% +//%PDDM-DEFINE GROUP_CLEANUP2() +//% [group release]; +//% +//%PDDM-DEFINE GROUP_TEST2() +//%TEST_ROUNDTRIP_ONEOF_ADV(Message2, Group, group, Objects) +//% +//%PDDM-DEFINE GROUP_INIT3() +// Empty +//%PDDM-DEFINE GROUP_CLEANUP3() +// Empty +//%PDDM-DEFINE GROUP_TEST3() +//% // Not "group" in proto3. +//% +//% +//%PDDM-EXPAND TEST_ROUNDTRIP_ONEOFS(2, NO) +// This block of code is generated, do not edit it directly. + +- (void)testProto2RoundTripOneof { + + Message2_OneofGroup *group = [[Message2_OneofGroup alloc] init]; + XCTAssertNotNil(group); + group.a = 777; + Message2 *subMessage = [[Message2 alloc] init]; + XCTAssertNotNil(subMessage); + subMessage.optionalInt32 = 666; + + { // oneofInt32 + Message2 *orig = [[Message2 alloc] init]; + orig.oneofInt32 = 1; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofInt32); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofInt32); + XCTAssertEqual(msg.oneofInt32, 1); + [orig release]; + } + + { // oneofInt64 + Message2 *orig = [[Message2 alloc] init]; + orig.oneofInt64 = 2; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofInt64); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofInt64); + XCTAssertEqual(msg.oneofInt64, 2); + [orig release]; + } + + { // oneofUint32 + Message2 *orig = [[Message2 alloc] init]; + orig.oneofUint32 = 3U; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofUint32); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofUint32); + XCTAssertEqual(msg.oneofUint32, 3U); + [orig release]; + } + + { // oneofUint64 + Message2 *orig = [[Message2 alloc] init]; + orig.oneofUint64 = 4U; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofUint64); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofUint64); + XCTAssertEqual(msg.oneofUint64, 4U); + [orig release]; + } + + { // oneofSint32 + Message2 *orig = [[Message2 alloc] init]; + orig.oneofSint32 = 5; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofSint32); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSint32); + XCTAssertEqual(msg.oneofSint32, 5); + [orig release]; + } + + { // oneofSint64 + Message2 *orig = [[Message2 alloc] init]; + orig.oneofSint64 = 6; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofSint64); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSint64); + XCTAssertEqual(msg.oneofSint64, 6); + [orig release]; + } + + { // oneofFixed32 + Message2 *orig = [[Message2 alloc] init]; + orig.oneofFixed32 = 7U; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofFixed32); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFixed32); + XCTAssertEqual(msg.oneofFixed32, 7U); + [orig release]; + } + + { // oneofFixed64 + Message2 *orig = [[Message2 alloc] init]; + orig.oneofFixed64 = 8U; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofFixed64); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFixed64); + XCTAssertEqual(msg.oneofFixed64, 8U); + [orig release]; + } + + { // oneofSfixed32 + Message2 *orig = [[Message2 alloc] init]; + orig.oneofSfixed32 = 9; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofSfixed32); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSfixed32); + XCTAssertEqual(msg.oneofSfixed32, 9); + [orig release]; + } + + { // oneofSfixed64 + Message2 *orig = [[Message2 alloc] init]; + orig.oneofSfixed64 = 10; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofSfixed64); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSfixed64); + XCTAssertEqual(msg.oneofSfixed64, 10); + [orig release]; + } + + { // oneofFloat + Message2 *orig = [[Message2 alloc] init]; + orig.oneofFloat = 11.0f; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofFloat); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFloat); + XCTAssertEqual(msg.oneofFloat, 11.0f); + [orig release]; + } + + { // oneofDouble + Message2 *orig = [[Message2 alloc] init]; + orig.oneofDouble = 12.0; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofDouble); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofDouble); + XCTAssertEqual(msg.oneofDouble, 12.0); + [orig release]; + } + + { // oneofBool + Message2 *orig = [[Message2 alloc] init]; + orig.oneofBool = NO; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofBool); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofBool); + XCTAssertEqual(msg.oneofBool, NO); + [orig release]; + } + + { // oneofString + Message2 *orig = [[Message2 alloc] init]; + orig.oneofString = @"foo"; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofString); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofString); + XCTAssertEqualObjects(msg.oneofString, @"foo"); + [orig release]; + } + + { // oneofBytes + Message2 *orig = [[Message2 alloc] init]; + orig.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding]; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofBytes); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofBytes); + XCTAssertEqualObjects(msg.oneofBytes, [@"bar" dataUsingEncoding:NSUTF8StringEncoding]); + [orig release]; + } + + { // oneofGroup + Message2 *orig = [[Message2 alloc] init]; + orig.oneofGroup = group; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofGroup); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofGroup); + XCTAssertEqualObjects(msg.oneofGroup, group); + [orig release]; + } + + { // oneofMessage + Message2 *orig = [[Message2 alloc] init]; + orig.oneofMessage = subMessage; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofMessage); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofMessage); + XCTAssertEqualObjects(msg.oneofMessage, subMessage); + [orig release]; + } + + { // oneofEnum + Message2 *orig = [[Message2 alloc] init]; + orig.oneofEnum = Message2_Enum_Bar; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofEnum); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofEnum); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Bar); + [orig release]; + } + + [group release]; + [subMessage release]; +} + +//%PDDM-EXPAND TEST_ROUNDTRIP_ONEOFS(3, YES) +// This block of code is generated, do not edit it directly. + +- (void)testProto3RoundTripOneof { + + Message3 *subMessage = [[Message3 alloc] init]; + XCTAssertNotNil(subMessage); + subMessage.optionalInt32 = 666; + + { // oneofInt32 + Message3 *orig = [[Message3 alloc] init]; + orig.oneofInt32 = 1; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofInt32); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofInt32); + XCTAssertEqual(msg.oneofInt32, 1); + [orig release]; + } + + { // oneofInt64 + Message3 *orig = [[Message3 alloc] init]; + orig.oneofInt64 = 2; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofInt64); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofInt64); + XCTAssertEqual(msg.oneofInt64, 2); + [orig release]; + } + + { // oneofUint32 + Message3 *orig = [[Message3 alloc] init]; + orig.oneofUint32 = 3U; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofUint32); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofUint32); + XCTAssertEqual(msg.oneofUint32, 3U); + [orig release]; + } + + { // oneofUint64 + Message3 *orig = [[Message3 alloc] init]; + orig.oneofUint64 = 4U; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofUint64); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofUint64); + XCTAssertEqual(msg.oneofUint64, 4U); + [orig release]; + } + + { // oneofSint32 + Message3 *orig = [[Message3 alloc] init]; + orig.oneofSint32 = 5; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofSint32); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSint32); + XCTAssertEqual(msg.oneofSint32, 5); + [orig release]; + } + + { // oneofSint64 + Message3 *orig = [[Message3 alloc] init]; + orig.oneofSint64 = 6; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofSint64); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSint64); + XCTAssertEqual(msg.oneofSint64, 6); + [orig release]; + } + + { // oneofFixed32 + Message3 *orig = [[Message3 alloc] init]; + orig.oneofFixed32 = 7U; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofFixed32); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFixed32); + XCTAssertEqual(msg.oneofFixed32, 7U); + [orig release]; + } + + { // oneofFixed64 + Message3 *orig = [[Message3 alloc] init]; + orig.oneofFixed64 = 8U; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofFixed64); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFixed64); + XCTAssertEqual(msg.oneofFixed64, 8U); + [orig release]; + } + + { // oneofSfixed32 + Message3 *orig = [[Message3 alloc] init]; + orig.oneofSfixed32 = 9; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofSfixed32); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSfixed32); + XCTAssertEqual(msg.oneofSfixed32, 9); + [orig release]; + } + + { // oneofSfixed64 + Message3 *orig = [[Message3 alloc] init]; + orig.oneofSfixed64 = 10; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofSfixed64); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSfixed64); + XCTAssertEqual(msg.oneofSfixed64, 10); + [orig release]; + } + + { // oneofFloat + Message3 *orig = [[Message3 alloc] init]; + orig.oneofFloat = 11.0f; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofFloat); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFloat); + XCTAssertEqual(msg.oneofFloat, 11.0f); + [orig release]; + } + + { // oneofDouble + Message3 *orig = [[Message3 alloc] init]; + orig.oneofDouble = 12.0; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofDouble); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofDouble); + XCTAssertEqual(msg.oneofDouble, 12.0); + [orig release]; + } + + { // oneofBool + Message3 *orig = [[Message3 alloc] init]; + orig.oneofBool = YES; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofBool); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofBool); + XCTAssertEqual(msg.oneofBool, YES); + [orig release]; + } + + { // oneofString + Message3 *orig = [[Message3 alloc] init]; + orig.oneofString = @"foo"; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofString); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofString); + XCTAssertEqualObjects(msg.oneofString, @"foo"); + [orig release]; + } + + { // oneofBytes + Message3 *orig = [[Message3 alloc] init]; + orig.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding]; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofBytes); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofBytes); + XCTAssertEqualObjects(msg.oneofBytes, [@"bar" dataUsingEncoding:NSUTF8StringEncoding]); + [orig release]; + } + + // Not "group" in proto3. + + { // oneofMessage + Message3 *orig = [[Message3 alloc] init]; + orig.oneofMessage = subMessage; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofMessage); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofMessage); + XCTAssertEqualObjects(msg.oneofMessage, subMessage); + [orig release]; + } + + { // oneofEnum + Message3 *orig = [[Message3 alloc] init]; + orig.oneofEnum = Message2_Enum_Bar; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofEnum); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofEnum); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Bar); + [orig release]; + } + + [subMessage release]; +} + +//%PDDM-EXPAND-END (2 expansions) + +#pragma mark - Subset from from map_tests.cc + +// TEST(GeneratedMapFieldTest, StandardWireFormat) +- (void)testMap_StandardWireFormat { + NSData *data = DataFromCStr("\x0A\x04\x08\x01\x10\x01"); + + TestMap *msg = [[TestMap alloc] initWithData:data]; + XCTAssertEqual(msg.mapInt32Int32.count, 1U); + int32_t val = 666; + XCTAssertTrue([msg.mapInt32Int32 valueForKey:1 value:&val]); + XCTAssertEqual(val, 1); + + [msg release]; +} + +// TEST(GeneratedMapFieldTest, UnorderedWireFormat) +- (void)testMap_UnorderedWireFormat { + // put value before key in wire format + NSData *data = DataFromCStr("\x0A\x04\x10\x01\x08\x02"); + + TestMap *msg = [[TestMap alloc] initWithData:data]; + XCTAssertEqual(msg.mapInt32Int32.count, 1U); + int32_t val = 666; + XCTAssertTrue([msg.mapInt32Int32 valueForKey:2 value:&val]); + XCTAssertEqual(val, 1); + + [msg release]; +} + +// TEST(GeneratedMapFieldTest, DuplicatedKeyWireFormat) +- (void)testMap_DuplicatedKeyWireFormat { + // Two key fields in wire format + NSData *data = DataFromCStr("\x0A\x06\x08\x01\x08\x02\x10\x01"); + + TestMap *msg = [[TestMap alloc] initWithData:data]; + XCTAssertEqual(msg.mapInt32Int32.count, 1U); + int32_t val = 666; + XCTAssertTrue([msg.mapInt32Int32 valueForKey:2 value:&val]); + XCTAssertEqual(val, 1); + + [msg release]; +} + +// TEST(GeneratedMapFieldTest, DuplicatedValueWireFormat) +- (void)testMap_DuplicatedValueWireFormat { + // Two value fields in wire format + NSData *data = DataFromCStr("\x0A\x06\x08\x01\x10\x01\x10\x02"); + + TestMap *msg = [[TestMap alloc] initWithData:data]; + XCTAssertEqual(msg.mapInt32Int32.count, 1U); + int32_t val = 666; + XCTAssertTrue([msg.mapInt32Int32 valueForKey:1 value:&val]); + XCTAssertEqual(val, 2); + + [msg release]; +} + +// TEST(GeneratedMapFieldTest, MissedKeyWireFormat) +- (void)testMap_MissedKeyWireFormat { + // No key field in wire format + NSData *data = DataFromCStr("\x0A\x02\x10\x01"); + + TestMap *msg = [[TestMap alloc] initWithData:data]; + XCTAssertEqual(msg.mapInt32Int32.count, 1U); + int32_t val = 666; + XCTAssertTrue([msg.mapInt32Int32 valueForKey:0 value:&val]); + XCTAssertEqual(val, 1); + + [msg release]; +} + +// TEST(GeneratedMapFieldTest, MissedValueWireFormat) +- (void)testMap_MissedValueWireFormat { + // No value field in wire format + NSData *data = DataFromCStr("\x0A\x02\x08\x01"); + + TestMap *msg = [[TestMap alloc] initWithData:data]; + XCTAssertEqual(msg.mapInt32Int32.count, 1U); + int32_t val = 666; + XCTAssertTrue([msg.mapInt32Int32 valueForKey:1 value:&val]); + XCTAssertEqual(val, 0); + + [msg release]; +} + +// TEST(GeneratedMapFieldTest, UnknownFieldWireFormat) +- (void)testMap_UnknownFieldWireFormat { + // Unknown field in wire format + NSData *data = DataFromCStr("\x0A\x06\x08\x02\x10\x03\x18\x01"); + + TestMap *msg = [[TestMap alloc] initWithData:data]; + XCTAssertEqual(msg.mapInt32Int32.count, 1U); + int32_t val = 666; + XCTAssertTrue([msg.mapInt32Int32 valueForKey:2 value:&val]); + XCTAssertEqual(val, 3); + + [msg release]; +} + +// TEST(GeneratedMapFieldTest, CorruptedWireFormat) +- (void)testMap_CorruptedWireFormat { + // corrupted data in wire format + NSData *data = DataFromCStr("\x0A\x06\x08\x02\x11\x03"); + + XCTAssertThrowsSpecificNamed([TestMap parseFromData:data], NSException, + NSParseErrorException); +} + +// TEST(GeneratedMapFieldTest, Proto2UnknownEnum) +- (void)testMap_Proto2UnknownEnum { + TestEnumMapPlusExtra *orig = [[TestEnumMapPlusExtra alloc] init]; + + orig.knownMapField = [GPBInt32EnumDictionary + dictionaryWithValidationFunction:Proto2MapEnumPlusExtra_IsValidValue]; + orig.unknownMapField = [GPBInt32EnumDictionary + dictionaryWithValidationFunction:Proto2MapEnumPlusExtra_IsValidValue]; + [orig.knownMapField setValue:Proto2MapEnumPlusExtra_EProto2MapEnumFoo + forKey:0]; + [orig.unknownMapField setValue:Proto2MapEnumPlusExtra_EProto2MapEnumExtra + forKey:0]; + + TestEnumMap *msg1 = [TestEnumMap parseFromData:[orig data]]; + XCTAssertEqual(msg1.knownMapField.count, 1U); + int32_t val = -1; + XCTAssertTrue([msg1.knownMapField valueForKey:0 value:&val]); + XCTAssertEqual(val, Proto2MapEnum_Proto2MapEnumFoo); + XCTAssertEqual(msg1.unknownFields.countOfFields, 1U); + + TestEnumMapPlusExtra *msg2 = [TestEnumMapPlusExtra parseFromData:[msg1 data]]; + val = -1; + XCTAssertEqual(msg2.knownMapField.count, 1U); + XCTAssertTrue([msg2.knownMapField valueForKey:0 value:&val]); + XCTAssertEqual(val, Proto2MapEnumPlusExtra_EProto2MapEnumFoo); + val = -1; + XCTAssertEqual(msg2.unknownMapField.count, 1U); + XCTAssertTrue([msg2.unknownMapField valueForKey:0 value:&val]); + XCTAssertEqual(val, Proto2MapEnumPlusExtra_EProto2MapEnumExtra); + XCTAssertEqual(msg2.unknownFields.countOfFields, 0U); + + XCTAssertEqualObjects(orig, msg2); + + [orig release]; +} + +#pragma mark - + +@end diff --git a/objectivec/Tests/GPBMessageTests.m b/objectivec/Tests/GPBMessageTests.m new file mode 100644 index 00000000..5ec67cd9 --- /dev/null +++ b/objectivec/Tests/GPBMessageTests.m @@ -0,0 +1,1728 @@ +// 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. + +#import "GPBTestUtilities.h" + +#import <objc/runtime.h> + +#import "GPBArray_PackagePrivate.h" +#import "GPBDescriptor.h" +#import "GPBField_PackagePrivate.h" +#import "GPBMessage_PackagePrivate.h" +#import "GPBUnknownFieldSet_PackagePrivate.h" +#import "google/protobuf/Unittest.pbobjc.h" +#import "google/protobuf/UnittestObjc.pbobjc.h" +#import "google/protobuf/UnittestNameMangling.pbobjc.h" + +@interface MessageTests : GPBTestCase +@end + +@implementation MessageTests + +// TODO(thomasvl): this should get split into a few files of logic junks, it is +// a jumble +// of things at the moment (and the testutils have a bunch of the real +// assertions). + +#ifdef DEBUG +- (void)assertBlock:(void (^)())block + throwsWithMessageInUserInfo:(GPBMessage *)message { + @try { + block(); + XCTAssertTrue(NO); + } + @catch (NSException *e) { + XCTAssertEqualObjects([e userInfo][GPBExceptionMessageKey], message); + } +} +#endif // DEBUG + +- (TestAllTypes *)mergeSource { + TestAllTypes *message = [TestAllTypes message]; + [message setOptionalInt32:1]; + [message setOptionalString:@"foo"]; + [message setOptionalForeignMessage:[ForeignMessage message]]; + message.repeatedStringArray = [NSMutableArray array]; + [message.repeatedStringArray addObject:@"bar"]; + return message; +} + +- (TestAllTypes *)mergeDestination { + TestAllTypes *message = [TestAllTypes message]; + [message setOptionalInt64:2]; + [message setOptionalString:@"baz"]; + ForeignMessage *foreignMessage = [ForeignMessage message]; + [foreignMessage setC:3]; + [message setOptionalForeignMessage:foreignMessage]; + message.repeatedStringArray = [NSMutableArray array]; + [message.repeatedStringArray addObject:@"qux"]; + return message; +} + +- (TestAllTypes *)mergeDestinationWithoutForeignMessageIvar { + TestAllTypes *message = [TestAllTypes message]; + [message setOptionalInt64:2]; + [message setOptionalString:@"baz"]; + message.repeatedStringArray = [NSMutableArray array]; + [message.repeatedStringArray addObject:@"qux"]; + return message; +} + +- (TestAllTypes *)mergeResult { + TestAllTypes *message = [TestAllTypes message]; + [message setOptionalInt32:1]; + [message setOptionalInt64:2]; + [message setOptionalString:@"foo"]; + ForeignMessage *foreignMessage = [ForeignMessage message]; + [foreignMessage setC:3]; + [message setOptionalForeignMessage:foreignMessage]; + message.repeatedStringArray = [NSMutableArray array]; + [message.repeatedStringArray addObject:@"qux"]; + [message.repeatedStringArray addObject:@"bar"]; + return message; +} + +- (TestAllTypes *)mergeResultForDestinationWithoutForeignMessageIvar { + TestAllTypes *message = [TestAllTypes message]; + [message setOptionalInt32:1]; + [message setOptionalInt64:2]; + [message setOptionalString:@"foo"]; + ForeignMessage *foreignMessage = [ForeignMessage message]; + [message setOptionalForeignMessage:foreignMessage]; + message.repeatedStringArray = [NSMutableArray array]; + [message.repeatedStringArray addObject:@"qux"]; + [message.repeatedStringArray addObject:@"bar"]; + return message; +} + +- (TestAllExtensions *)mergeExtensionsDestination { + TestAllExtensions *message = [TestAllExtensions message]; + [message setExtension:[UnittestRoot optionalInt32Extension] value:@5]; + [message setExtension:[UnittestRoot optionalStringExtension] value:@"foo"]; + ForeignMessage *foreignMessage = [ForeignMessage message]; + foreignMessage.c = 4; + [message setExtension:[UnittestRoot optionalForeignMessageExtension] + value:foreignMessage]; + TestAllTypes_NestedMessage *nestedMessage = + [TestAllTypes_NestedMessage message]; + [message setExtension:[UnittestRoot optionalNestedMessageExtension] + value:nestedMessage]; + return message; +} + +- (TestAllExtensions *)mergeExtensionsSource { + TestAllExtensions *message = [TestAllExtensions message]; + [message setExtension:[UnittestRoot optionalInt64Extension] value:@6]; + [message setExtension:[UnittestRoot optionalStringExtension] value:@"bar"]; + ForeignMessage *foreignMessage = [ForeignMessage message]; + [message setExtension:[UnittestRoot optionalForeignMessageExtension] + value:foreignMessage]; + TestAllTypes_NestedMessage *nestedMessage = + [TestAllTypes_NestedMessage message]; + nestedMessage.bb = 7; + [message setExtension:[UnittestRoot optionalNestedMessageExtension] + value:nestedMessage]; + return message; +} + +- (TestAllExtensions *)mergeExtensionsResult { + TestAllExtensions *message = [TestAllExtensions message]; + [message setExtension:[UnittestRoot optionalInt32Extension] value:@5]; + [message setExtension:[UnittestRoot optionalInt64Extension] value:@6]; + [message setExtension:[UnittestRoot optionalStringExtension] value:@"bar"]; + ForeignMessage *foreignMessage = [ForeignMessage message]; + foreignMessage.c = 4; + [message setExtension:[UnittestRoot optionalForeignMessageExtension] + value:foreignMessage]; + TestAllTypes_NestedMessage *nestedMessage = + [TestAllTypes_NestedMessage message]; + nestedMessage.bb = 7; + [message setExtension:[UnittestRoot optionalNestedMessageExtension] + value:nestedMessage]; + return message; +} + +- (void)testMergeFrom { + TestAllTypes *result = [[self.mergeDestination copy] autorelease]; + [result mergeFrom:self.mergeSource]; + NSData *resultData = [result data]; + NSData *mergeResultData = [self.mergeResult data]; + XCTAssertEqualObjects(resultData, mergeResultData); + XCTAssertEqualObjects(result, self.mergeResult); + + // Test when destination does not have an Ivar (type is an object) but source + // has such Ivar. + // The result must has the Ivar which is same as the one in source. + result = [[self.mergeDestinationWithoutForeignMessageIvar copy] autorelease]; + [result mergeFrom:self.mergeSource]; + resultData = [result data]; + mergeResultData = + [self.mergeResultForDestinationWithoutForeignMessageIvar data]; + XCTAssertEqualObjects(resultData, mergeResultData); + XCTAssertEqualObjects( + result, self.mergeResultForDestinationWithoutForeignMessageIvar); + + // Test when destination is empty. + // The result must is same as the source. + result = [TestAllTypes message]; + [result mergeFrom:self.mergeSource]; + resultData = [result data]; + mergeResultData = [self.mergeSource data]; + XCTAssertEqualObjects(resultData, mergeResultData); + XCTAssertEqualObjects(result, self.mergeSource); +} + +- (void)testMergeFromWithExtensions { + TestAllExtensions *result = [self mergeExtensionsDestination]; + [result mergeFrom:[self mergeExtensionsSource]]; + NSData *resultData = [result data]; + NSData *mergeResultData = [[self mergeExtensionsResult] data]; + XCTAssertEqualObjects(resultData, mergeResultData); + XCTAssertEqualObjects(result, [self mergeExtensionsResult]); + + // Test merging from data. + result = [self mergeExtensionsDestination]; + [result mergeFromData:[[self mergeExtensionsSource] data] + extensionRegistry:[UnittestRoot extensionRegistry]]; + resultData = [result data]; + XCTAssertEqualObjects(resultData, mergeResultData); + XCTAssertEqualObjects(result, [self mergeExtensionsResult]); +} + +- (void)testIsEquals { + TestAllTypes *result = [[self.mergeDestination copy] autorelease]; + [result mergeFrom:self.mergeSource]; + XCTAssertEqualObjects(result.data, self.mergeResult.data); + XCTAssertEqualObjects(result, self.mergeResult); + TestAllTypes *result2 = [[self.mergeDestination copy] autorelease]; + XCTAssertNotEqualObjects(result2.data, self.mergeResult.data); + XCTAssertNotEqualObjects(result2, self.mergeResult); +} + +// ================================================================= +// Required-field-related tests. + +- (TestRequired *)testRequiredInitialized { + TestRequired *message = [TestRequired message]; + [message setA:1]; + [message setB:2]; + [message setC:3]; + return message; +} + +- (void)testRequired { + TestRequired *message = [TestRequired message]; + + XCTAssertFalse(message.initialized); + [message setA:1]; + XCTAssertFalse(message.initialized); + [message setB:1]; + XCTAssertFalse(message.initialized); + [message setC:1]; + XCTAssertTrue(message.initialized); +} + +- (void)testRequiredForeign { + TestRequiredForeign *message = [TestRequiredForeign message]; + + XCTAssertTrue(message.initialized); + + [message setOptionalMessage:[TestRequired message]]; + XCTAssertFalse(message.initialized); + + [message setOptionalMessage:self.testRequiredInitialized]; + XCTAssertTrue(message.initialized); + + message.repeatedMessageArray = [NSMutableArray array]; + [message.repeatedMessageArray addObject:[TestRequired message]]; + XCTAssertFalse(message.initialized); + + [message.repeatedMessageArray removeAllObjects]; + [message.repeatedMessageArray addObject:self.testRequiredInitialized]; + XCTAssertTrue(message.initialized); +} + +- (void)testRequiredExtension { + TestAllExtensions *message = [TestAllExtensions message]; + + XCTAssertTrue(message.initialized); + + [message setExtension:[TestRequired single] value:[TestRequired message]]; + XCTAssertFalse(message.initialized); + + [message setExtension:[TestRequired single] + value:self.testRequiredInitialized]; + XCTAssertTrue(message.initialized); + + [message addExtension:[TestRequired multi] value:[TestRequired message]]; + XCTAssertFalse(message.initialized); + + [message setExtension:[TestRequired multi] + index:0 + value:self.testRequiredInitialized]; + XCTAssertTrue(message.initialized); +} + +#ifdef DEBUG +- (void)testUninitializedException { + TestRequired *message = [TestRequired message]; + [self assertBlock:^{ + [message data]; + } throwsWithMessageInUserInfo:message]; +} +#endif // DEBUG + +- (void)testInitialized { + // We're mostly testing that no exception is thrown. + TestRequired *message = [TestRequired message]; + XCTAssertFalse(message.initialized); +} + +#ifdef DEBUG +- (void)testNestedUninitializedException { + TestRequiredForeign *message = [TestRequiredForeign message]; + [message setOptionalMessage:[TestRequired message]]; + message.repeatedMessageArray = [NSMutableArray array]; + [message.repeatedMessageArray addObject:[TestRequired message]]; + [message.repeatedMessageArray addObject:[TestRequired message]]; + [self assertBlock:^{ + [message data]; + } throwsWithMessageInUserInfo:message]; +} +#endif // DEBUG + +- (void)testNestedInitialized { + // We're mostly testing that no exception is thrown. + + TestRequiredForeign *message = [TestRequiredForeign message]; + [message setOptionalMessage:[TestRequired message]]; + message.repeatedMessageArray = [NSMutableArray array]; + [message.repeatedMessageArray addObject:[TestRequired message]]; + [message.repeatedMessageArray addObject:[TestRequired message]]; + + XCTAssertFalse(message.initialized); +} + +#ifdef DEBUG +- (void)testParseUninitialized { + [self assertBlock:^{ + [TestRequired parseFromData:GPBEmptyNSData()]; + } throwsWithMessageInUserInfo:[TestRequired message]]; +} +#endif // DEBUG + +- (void)testCoding { + NSData *data = + [NSKeyedArchiver archivedDataWithRootObject:[self mergeResult]]; + id unarchivedObject = [NSKeyedUnarchiver unarchiveObjectWithData:data]; + + XCTAssertEqualObjects(unarchivedObject, [self mergeResult]); + + // Intentionally doing a pointer comparison. + XCTAssertNotEqual(unarchivedObject, [self mergeResult]); +} + +- (void)testObjectReset { + // Tests a failure where clearing out defaults values caused an over release. + TestAllTypes *message = [TestAllTypes message]; + message.hasOptionalNestedMessage = NO; + [message setOptionalNestedMessage:[TestAllTypes_NestedMessage message]]; + message.hasOptionalNestedMessage = NO; + [message setOptionalNestedMessage:[TestAllTypes_NestedMessage message]]; + [message setOptionalNestedMessage:nil]; + message.hasOptionalNestedMessage = NO; +} + +- (void)testSettingHasToYes { + TestAllTypes *message = [TestAllTypes message]; + XCTAssertThrows([message setHasOptionalNestedMessage:YES]); +} + +- (void)testRoot { + XCTAssertNotNil([UnittestRoot extensionRegistry]); +} + +- (void)testGPBMessageSize { + // See the note in GPBMessage_PackagePrivate.h about why we want to keep the + // base instance size pointer size aligned. + size_t messageSize = class_getInstanceSize([GPBMessage class]); + XCTAssertEqual((messageSize % sizeof(void *)), (size_t)0, + @"Base size isn't pointer size aligned"); + + // Since we add storage ourselves (see +allocWithZone: in GPBMessage), confirm + // that the size of some generated classes is still the same as the base for + // that logic to work as desired. + size_t testMessageSize = class_getInstanceSize([TestAllTypes class]); + XCTAssertEqual(testMessageSize, messageSize); +} + +- (void)testInit { + TestAllTypes *message = [TestAllTypes message]; + [self assertClear:message]; +} + +- (void)testAccessors { + TestAllTypes *message = [TestAllTypes message]; + [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount]; + [self assertAllFieldsSet:message repeatedCount:kGPBDefaultRepeatCount]; +} + +- (void)testKVC_ValueForKey { + TestAllTypes *message = [TestAllTypes message]; + [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount]; + [self assertAllFieldsKVCMatch:message]; +} + +- (void)testKVC_SetValue_ForKey { + TestAllTypes *message = [TestAllTypes message]; + [self setAllFieldsViaKVC:message repeatedCount:kGPBDefaultRepeatCount]; + [self assertAllFieldsKVCMatch:message]; + [self assertAllFieldsSet:message repeatedCount:kGPBDefaultRepeatCount]; + [self assertAllFieldsKVCMatch:message]; +} + +- (void)testDescription { + // No real test, just exercise code + TestAllTypes *message = [TestAllTypes message]; + [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount]; + + GPBUnknownFieldSet *unknownFields = + [[[GPBUnknownFieldSet alloc] init] autorelease]; + GPBField *field = [[[GPBField alloc] initWithNumber:2] autorelease]; + [field addVarint:2]; + [unknownFields addField:field]; + field = [[[GPBField alloc] initWithNumber:3] autorelease]; + [field addVarint:4]; + [unknownFields addField:field]; + + [message setUnknownFields:unknownFields]; + + NSString *description = [message description]; + XCTAssertGreaterThan([description length], 0U); + + GPBMessage *message2 = [TestAllExtensions message]; + [message2 setExtension:[UnittestRoot optionalInt32Extension] value:@1]; + + [message2 addExtension:[UnittestRoot repeatedInt32Extension] value:@2]; + + description = [message2 description]; + XCTAssertGreaterThan([description length], 0U); +} + +- (void)testSetter { + // Test to make sure that if we set a value that has a default value + // with the default, that the has is set, and the value gets put into the + // message correctly. + TestAllTypes *message = [TestAllTypes message]; + GPBDescriptor *descriptor = [[message class] descriptor]; + XCTAssertNotNil(descriptor); + GPBFieldDescriptor *fieldDescriptor = + [descriptor fieldWithName:@"defaultInt32"]; + XCTAssertNotNil(fieldDescriptor); + GPBValue defaultValue = [fieldDescriptor defaultValue]; + [message setDefaultInt32:defaultValue.valueInt32]; + XCTAssertTrue(message.hasDefaultInt32); + XCTAssertEqual(message.defaultInt32, defaultValue.valueInt32); + + // Do the same thing with an object type. + message = [TestAllTypes message]; + fieldDescriptor = [descriptor fieldWithName:@"defaultString"]; + XCTAssertNotNil(fieldDescriptor); + defaultValue = [fieldDescriptor defaultValue]; + [message setDefaultString:defaultValue.valueString]; + XCTAssertTrue(message.hasDefaultString); + XCTAssertEqualObjects(message.defaultString, defaultValue.valueString); + + // Test default string type. + message = [TestAllTypes message]; + XCTAssertEqualObjects(message.defaultString, @"hello"); + XCTAssertFalse(message.hasDefaultString); + fieldDescriptor = [descriptor fieldWithName:@"defaultString"]; + XCTAssertNotNil(fieldDescriptor); + defaultValue = [fieldDescriptor defaultValue]; + [message setDefaultString:defaultValue.valueString]; + XCTAssertEqualObjects(message.defaultString, @"hello"); + XCTAssertTrue(message.hasDefaultString); + [message setDefaultString:nil]; + XCTAssertEqualObjects(message.defaultString, @"hello"); + XCTAssertFalse(message.hasDefaultString); + message.hasDefaultString = NO; + XCTAssertFalse(message.hasDefaultString); + XCTAssertEqualObjects(message.defaultString, @"hello"); + + // Test default bytes type. + NSData *defaultBytes = [@"world" dataUsingEncoding:NSUTF8StringEncoding]; + XCTAssertEqualObjects(message.defaultBytes, defaultBytes); + XCTAssertFalse(message.hasDefaultString); + fieldDescriptor = [descriptor fieldWithName:@"defaultBytes"]; + XCTAssertNotNil(fieldDescriptor); + defaultValue = [fieldDescriptor defaultValue]; + [message setDefaultBytes:defaultValue.valueData]; + XCTAssertEqualObjects(message.defaultBytes, defaultBytes); + XCTAssertTrue(message.hasDefaultBytes); + [message setDefaultBytes:nil]; + XCTAssertEqualObjects(message.defaultBytes, defaultBytes); + XCTAssertFalse(message.hasDefaultBytes); + message.hasDefaultBytes = NO; + XCTAssertFalse(message.hasDefaultBytes); + XCTAssertEqualObjects(message.defaultBytes, defaultBytes); + + // Test optional string. + XCTAssertFalse(message.hasOptionalString); + XCTAssertEqualObjects(message.optionalString, @""); + XCTAssertFalse(message.hasOptionalString); + message.optionalString = nil; + XCTAssertFalse(message.hasOptionalString); + XCTAssertEqualObjects(message.optionalString, @""); + NSString *string = @"string"; + message.optionalString = string; + XCTAssertEqualObjects(message.optionalString, string); + XCTAssertTrue(message.hasOptionalString); + message.optionalString = nil; + XCTAssertFalse(message.hasOptionalString); + XCTAssertEqualObjects(message.optionalString, @""); + + // Test optional data. + XCTAssertFalse(message.hasOptionalBytes); + XCTAssertEqualObjects(message.optionalBytes, GPBEmptyNSData()); + XCTAssertFalse(message.hasOptionalBytes); + message.optionalBytes = nil; + XCTAssertFalse(message.hasOptionalBytes); + XCTAssertEqualObjects(message.optionalBytes, GPBEmptyNSData()); + NSData *data = [@"bytes" dataUsingEncoding:NSUTF8StringEncoding]; + message.optionalBytes = data; + XCTAssertEqualObjects(message.optionalBytes, data); + XCTAssertTrue(message.hasOptionalBytes); + message.optionalBytes = nil; + XCTAssertFalse(message.hasOptionalBytes); + XCTAssertEqualObjects(message.optionalBytes, GPBEmptyNSData()); + + // Test lazy message setting + XCTAssertFalse(message.hasOptionalLazyMessage); + XCTAssertNotNil(message.optionalLazyMessage); + XCTAssertFalse(message.hasOptionalLazyMessage); + message.hasOptionalLazyMessage = NO; + XCTAssertFalse(message.hasOptionalLazyMessage); + XCTAssertNotNil(message.optionalLazyMessage); + XCTAssertFalse(message.hasOptionalLazyMessage); + message.optionalLazyMessage = nil; + XCTAssertFalse(message.hasOptionalLazyMessage); + + // Test nested messages + XCTAssertFalse(message.hasOptionalLazyMessage); + message.optionalLazyMessage.bb = 1; + XCTAssertTrue(message.hasOptionalLazyMessage); + XCTAssertEqual(message.optionalLazyMessage.bb, 1); + XCTAssertNotNil(message.optionalLazyMessage); + message.optionalLazyMessage = nil; + XCTAssertFalse(message.hasOptionalLazyMessage); + XCTAssertEqual(message.optionalLazyMessage.bb, 0); + XCTAssertFalse(message.hasOptionalLazyMessage); + XCTAssertNotNil(message.optionalLazyMessage); + + // -testDefaultSubMessages tests the "defaulting" handling of fields + // containing messages. +} + +- (void)testRepeatedSetters { + TestAllTypes *message = [TestAllTypes message]; + [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount]; + [self modifyRepeatedFields:message]; + [self assertRepeatedFieldsModified:message + repeatedCount:kGPBDefaultRepeatCount]; +} + +- (void)testClear { + TestAllTypes *message = [TestAllTypes message]; + [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount]; + [self clearAllFields:message]; + [self assertClear:message]; + TestAllTypes *message2 = [TestAllTypes message]; + XCTAssertEqualObjects(message, message2); +} + +- (void)testClearKVC { + TestAllTypes *message = [TestAllTypes message]; + [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount]; + [self clearAllFields:message]; + [self assertClear:message]; + [self assertClearKVC:message]; +} + +- (void)testClearExtension { + // clearExtension() is not actually used in TestUtil, so try it manually. + GPBMessage *message1 = [TestAllExtensions message]; + [message1 setExtension:[UnittestRoot optionalInt32Extension] value:@1]; + + XCTAssertTrue([message1 hasExtension:[UnittestRoot optionalInt32Extension]]); + [message1 clearExtension:[UnittestRoot optionalInt32Extension]]; + XCTAssertFalse([message1 hasExtension:[UnittestRoot optionalInt32Extension]]); + + GPBMessage *message2 = [TestAllExtensions message]; + [message2 addExtension:[UnittestRoot repeatedInt32Extension] value:@1]; + + XCTAssertEqual( + [[message2 getExtension:[UnittestRoot repeatedInt32Extension]] count], + (NSUInteger)1); + [message2 clearExtension:[UnittestRoot repeatedInt32Extension]]; + XCTAssertEqual( + [[message2 getExtension:[UnittestRoot repeatedInt32Extension]] count], + (NSUInteger)0); + + // Clearing an unset extension field shouldn't make the target message + // visible. + GPBMessage *message3 = [TestAllExtensions message]; + GPBMessage *extension_msg = + [message3 getExtension:[UnittestObjcRoot recursiveExtension]]; + XCTAssertFalse([message3 hasExtension:[UnittestObjcRoot recursiveExtension]]); + [extension_msg clearExtension:[UnittestRoot optionalInt32Extension]]; + XCTAssertFalse([message3 hasExtension:[UnittestObjcRoot recursiveExtension]]); +} + +- (void)testDefaultingSubMessages { + TestAllTypes *message = [TestAllTypes message]; + + // Initially they should all not have values. + + XCTAssertFalse(message.hasOptionalGroup); + XCTAssertFalse(message.hasOptionalNestedMessage); + XCTAssertFalse(message.hasOptionalForeignMessage); + XCTAssertFalse(message.hasOptionalImportMessage); + XCTAssertFalse(message.hasOptionalPublicImportMessage); + XCTAssertFalse(message.hasOptionalLazyMessage); + + // They should auto create something when fetched. + + TestAllTypes_OptionalGroup *optionalGroup = [message.optionalGroup retain]; + TestAllTypes_NestedMessage *optionalNestedMessage = + [message.optionalNestedMessage retain]; + ForeignMessage *optionalForeignMessage = + [message.optionalForeignMessage retain]; + ImportMessage *optionalImportMessage = [message.optionalImportMessage retain]; + PublicImportMessage *optionalPublicImportMessage = + [message.optionalPublicImportMessage retain]; + TestAllTypes_NestedMessage *optionalLazyMessage = + [message.optionalLazyMessage retain]; + + XCTAssertNotNil(optionalGroup); + XCTAssertNotNil(optionalNestedMessage); + XCTAssertNotNil(optionalForeignMessage); + XCTAssertNotNil(optionalImportMessage); + XCTAssertNotNil(optionalPublicImportMessage); + XCTAssertNotNil(optionalLazyMessage); + + // Although they were created, they should not respond to hasValue until that + // submessage is mutated. + + XCTAssertFalse(message.hasOptionalGroup); + XCTAssertFalse(message.hasOptionalNestedMessage); + XCTAssertFalse(message.hasOptionalForeignMessage); + XCTAssertFalse(message.hasOptionalImportMessage); + XCTAssertFalse(message.hasOptionalPublicImportMessage); + XCTAssertFalse(message.hasOptionalLazyMessage); + + // And they set that value back in to the message since the value created was + // mutable (so a second fetch should give the same object). + + XCTAssertEqual(message.optionalGroup, optionalGroup); + XCTAssertEqual(message.optionalNestedMessage, optionalNestedMessage); + XCTAssertEqual(message.optionalForeignMessage, optionalForeignMessage); + XCTAssertEqual(message.optionalImportMessage, optionalImportMessage); + XCTAssertEqual(message.optionalPublicImportMessage, + optionalPublicImportMessage); + XCTAssertEqual(message.optionalLazyMessage, optionalLazyMessage); + + // And the default objects for a second message should be distinct (again, + // since they are mutable, each needs their own copy). + + TestAllTypes *message2 = [TestAllTypes message]; + + // Intentionally doing a pointer comparison. + XCTAssertNotEqual(message2.optionalGroup, optionalGroup); + XCTAssertNotEqual(message2.optionalNestedMessage, optionalNestedMessage); + XCTAssertNotEqual(message2.optionalForeignMessage, optionalForeignMessage); + XCTAssertNotEqual(message2.optionalImportMessage, optionalImportMessage); + XCTAssertNotEqual(message2.optionalPublicImportMessage, + optionalPublicImportMessage); + XCTAssertNotEqual(message2.optionalLazyMessage, optionalLazyMessage); + + // Setting the values to nil will clear the has flag, and on next access you + // get back new submessages. + + message.optionalGroup = nil; + message.optionalNestedMessage = nil; + message.optionalForeignMessage = nil; + message.optionalImportMessage = nil; + message.optionalPublicImportMessage = nil; + message.optionalLazyMessage = nil; + + XCTAssertFalse(message.hasOptionalGroup); + XCTAssertFalse(message.hasOptionalNestedMessage); + XCTAssertFalse(message.hasOptionalForeignMessage); + XCTAssertFalse(message.hasOptionalImportMessage); + XCTAssertFalse(message.hasOptionalPublicImportMessage); + XCTAssertFalse(message.hasOptionalLazyMessage); + + // Intentionally doing a pointer comparison. + XCTAssertNotEqual(message.optionalGroup, optionalGroup); + XCTAssertNotEqual(message.optionalNestedMessage, optionalNestedMessage); + XCTAssertNotEqual(message.optionalForeignMessage, optionalForeignMessage); + XCTAssertNotEqual(message.optionalImportMessage, optionalImportMessage); + XCTAssertNotEqual(message.optionalPublicImportMessage, + optionalPublicImportMessage); + XCTAssertNotEqual(message.optionalLazyMessage, optionalLazyMessage); + + [optionalGroup release]; + [optionalNestedMessage release]; + [optionalForeignMessage release]; + [optionalImportMessage release]; + [optionalPublicImportMessage release]; + [optionalLazyMessage release]; +} + +- (void)testMultiplePointersToAutocreatedMessage { + // Multiple objects pointing to the same autocreated message. + TestAllTypes *message = [TestAllTypes message]; + TestAllTypes *message2 = [TestAllTypes message]; + message2.optionalGroup = message.optionalGroup; + XCTAssertTrue([message2 hasOptionalGroup]); + XCTAssertFalse([message hasOptionalGroup]); + message2.optionalGroup.a = 42; + XCTAssertTrue([message hasOptionalGroup]); + XCTAssertTrue([message2 hasOptionalGroup]); +} + +- (void)testCopyWithAutocreatedMessage { + // Mutable copy should not copy autocreated messages. + TestAllTypes *message = [TestAllTypes message]; + message.optionalGroup.a = 42; + XCTAssertNotNil(message.optionalNestedMessage); + TestAllTypes *message2 = [[message copy] autorelease]; + XCTAssertTrue([message2 hasOptionalGroup]); + XCTAssertFalse([message2 hasOptionalNestedMessage]); + + // Intentionally doing a pointer comparison. + XCTAssertNotEqual(message.optionalNestedMessage, + message2.optionalNestedMessage); +} + +- (void)testClearAutocreatedSubmessage { + // Call clear on an intermediate submessage should cause it to get recreated + // on the next call. + TestRecursiveMessage *message = [TestRecursiveMessage message]; + TestRecursiveMessage *message_inner = [message.a.a.a retain]; + XCTAssertNotNil(message_inner); + XCTAssertTrue(GPBWasMessageAutocreatedBy(message_inner, message.a.a)); + [message.a.a clear]; + XCTAssertFalse(GPBWasMessageAutocreatedBy(message_inner, message.a.a)); + + // Intentionally doing a pointer comparison. + XCTAssertNotEqual(message.a.a.a, message_inner); + [message_inner release]; +} + +- (void)testRetainAutocreatedSubmessage { + // Should be able to retain autocreated submessage while the creator is + // dealloced. + TestAllTypes *message = [TestAllTypes message]; + + ForeignMessage *subMessage; + @autoreleasepool { + TestAllTypes *message2 = [TestAllTypes message]; + subMessage = message2.optionalForeignMessage; // Autocreated + message.optionalForeignMessage = subMessage; + XCTAssertTrue(GPBWasMessageAutocreatedBy(message.optionalForeignMessage, + message2)); + } + + // Should be the same object, and should still be live. + XCTAssertEqual(message.optionalForeignMessage, subMessage); + XCTAssertNotNil([subMessage description]); +} + +- (void)testSetNilAutocreatedSubmessage { + TestRecursiveMessage *message = [TestRecursiveMessage message]; + TestRecursiveMessage *message_inner = [message.a.a retain]; + XCTAssertFalse([message hasA]); + XCTAssertFalse([message.a hasA]); + message.a.a = nil; + + // |message.a| has to be made visible, but |message.a.a| was set to nil so + // shouldn't be. + XCTAssertTrue([message hasA]); + XCTAssertFalse([message.a hasA]); + + // Setting submessage to nil should cause it to lose its creator. + XCTAssertFalse(GPBWasMessageAutocreatedBy(message_inner, message.a)); + + // After setting to nil, getting it again should create a new autocreated + // message. + // Intentionally doing a pointer comparison. + XCTAssertNotEqual(message.a.a, message_inner); + + [message_inner release]; +} + +- (void)testSetDoesntHaveAutocreatedSubmessage { + // Clearing submessage (set has == NO) should NOT cause it to lose its + // creator. + TestAllTypes *message = [TestAllTypes message]; + TestAllTypes_NestedMessage *nestedMessage = message.optionalNestedMessage; + XCTAssertFalse([message hasOptionalNestedMessage]); + [message setHasOptionalNestedMessage:NO]; + XCTAssertFalse([message hasOptionalNestedMessage]); + XCTAssertEqual(message.optionalNestedMessage, nestedMessage); +} + +- (void)testSetAutocreatedMessageBecomesVisible { + // Setting a value should cause the submessage to appear to its creator. + // Test this several levels deep. + TestRecursiveMessage *message = [TestRecursiveMessage message]; + message.a.a.a.a.i = 42; + XCTAssertTrue([message hasA]); + XCTAssertTrue([message.a hasA]); + XCTAssertTrue([message.a.a hasA]); + XCTAssertTrue([message.a.a.a hasA]); + XCTAssertFalse([message.a.a.a.a hasA]); + XCTAssertEqual(message.a.a.a.a.i, 42); +} + +- (void)testClearUnsetFieldOfAutocreatedMessage { + // Clearing an unset field should not cause the submessage to appear to its + // creator. + TestRecursiveMessage *message = [TestRecursiveMessage message]; + message.a.a.a.a.hasI = NO; + XCTAssertFalse([message hasA]); + XCTAssertFalse([message.a hasA]); + XCTAssertFalse([message.a.a hasA]); + XCTAssertFalse([message.a.a.a hasA]); +} + +- (void)testAutocreatedSubmessageAssignSkip { + TestRecursiveMessage *message = [TestRecursiveMessage message]; + TestRecursiveMessage *messageLevel1 = [message.a retain]; + TestRecursiveMessage *messageLevel2 = [message.a.a retain]; + TestRecursiveMessage *messageLevel3 = [message.a.a.a retain]; + TestRecursiveMessage *messageLevel4 = [message.a.a.a.a retain]; + XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel1, message)); + XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel2, messageLevel1)); + XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel3, messageLevel2)); + XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel4, messageLevel3)); + + // Test skipping over an autocreated submessage and ensure it gets unset. + message.a = message.a.a; + XCTAssertEqual(message.a, messageLevel2); + XCTAssertTrue([message hasA]); + XCTAssertEqual(message.a.a, messageLevel3); + XCTAssertFalse([message.a hasA]); + XCTAssertEqual(message.a.a.a, messageLevel4); + XCTAssertFalse(GPBWasMessageAutocreatedBy(messageLevel1, + message)); // Because it was orphaned. + XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel2, messageLevel1)); + XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel3, messageLevel2)); + + [messageLevel1 release]; + [messageLevel2 release]; + [messageLevel3 release]; + [messageLevel4 release]; +} + +- (void)testAutocreatedSubmessageAssignLoop { + TestRecursiveMessage *message = [TestRecursiveMessage message]; + TestRecursiveMessage *messageLevel1 = [message.a retain]; + TestRecursiveMessage *messageLevel2 = [message.a.a retain]; + TestRecursiveMessage *messageLevel3 = [message.a.a.a retain]; + TestRecursiveMessage *messageLevel4 = [message.a.a.a.a retain]; + XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel1, message)); + XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel2, messageLevel1)); + XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel3, messageLevel2)); + XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel4, messageLevel3)); + + // Test a property with a loop. You'd never do this but at least ensure the + // autocreated submessages behave sanely. + message.a.a = message.a; + XCTAssertTrue([message hasA]); + XCTAssertEqual(message.a, messageLevel1); + XCTAssertTrue([message.a hasA]); + XCTAssertEqual(message.a.a, messageLevel1); + XCTAssertTrue([message.a.a hasA]); + XCTAssertEqual(message.a.a.a, messageLevel1); + XCTAssertFalse(GPBWasMessageAutocreatedBy(messageLevel1, + message)); // Because it was assigned. + XCTAssertFalse(GPBWasMessageAutocreatedBy(messageLevel2, + messageLevel1)); // Because it was orphaned. + XCTAssertFalse([messageLevel2 hasA]); + + // Break the retain loop. + message.a.a = nil; + XCTAssertTrue([message hasA]); + XCTAssertFalse([message.a hasA]); + + [messageLevel1 release]; + [messageLevel2 release]; + [messageLevel3 release]; + [messageLevel4 release]; +} + +- (void)testSetAutocreatedSubmessage { + // Setting autocreated submessage to another value should cause the old one to + // lose its creator. + TestAllTypes *message = [TestAllTypes message]; + TestAllTypes_NestedMessage *nestedMessage = + [message.optionalNestedMessage retain]; + + message.optionalNestedMessage = [TestAllTypes_NestedMessage message]; + XCTAssertTrue([message hasOptionalNestedMessage]); + XCTAssertTrue(message.optionalNestedMessage != nestedMessage); + XCTAssertFalse(GPBWasMessageAutocreatedBy(nestedMessage, message)); + + [nestedMessage release]; +} + +- (void)testAutocreatedUnknownFields { + // Doing anything with (except reading) unknown fields should cause the + // submessage to become visible. + TestAllTypes *message = [TestAllTypes message]; + XCTAssertNotNil(message.optionalNestedMessage); + XCTAssertFalse([message hasOptionalNestedMessage]); + XCTAssertNil(message.optionalNestedMessage.unknownFields); + XCTAssertFalse([message hasOptionalNestedMessage]); + + GPBUnknownFieldSet *unknownFields = + [[[GPBUnknownFieldSet alloc] init] autorelease]; + message.optionalNestedMessage.unknownFields = unknownFields; + XCTAssertTrue([message hasOptionalNestedMessage]); + + message.optionalNestedMessage = nil; + XCTAssertFalse([message hasOptionalNestedMessage]); + [message.optionalNestedMessage setUnknownFields:unknownFields]; + XCTAssertTrue([message hasOptionalNestedMessage]); +} + +- (void)testSetAutocreatedSubmessageToSelf { + // Setting submessage to itself should cause it to become visible. + TestAllTypes *message = [TestAllTypes message]; + XCTAssertNotNil(message.optionalNestedMessage); + XCTAssertFalse([message hasOptionalNestedMessage]); + message.optionalNestedMessage = message.optionalNestedMessage; + XCTAssertTrue([message hasOptionalNestedMessage]); +} + +- (void)testAutocreatedSubmessageMemoryLeaks { + // Test for memory leaks with autocreated submessages. + TestRecursiveMessage *message; + TestRecursiveMessage *messageLevel1; + TestRecursiveMessage *messageLevel2; + TestRecursiveMessage *messageLevel3; + TestRecursiveMessage *messageLevel4; + @autoreleasepool { + message = [[TestRecursiveMessage alloc] init]; + messageLevel1 = [message.a retain]; + messageLevel2 = [message.a.a retain]; + messageLevel3 = [message.a.a.a retain]; + messageLevel4 = [message.a.a.a.a retain]; + message.a.i = 1; + } + + XCTAssertEqual(message.retainCount, (NSUInteger)1); + [message release]; + XCTAssertEqual(messageLevel1.retainCount, (NSUInteger)1); + [messageLevel1 release]; + XCTAssertEqual(messageLevel2.retainCount, (NSUInteger)1); + [messageLevel2 release]; + XCTAssertEqual(messageLevel3.retainCount, (NSUInteger)1); + [messageLevel3 release]; + XCTAssertEqual(messageLevel4.retainCount, (NSUInteger)1); + [messageLevel4 release]; +} + +- (void)testDefaultingArrays { + // Basic tests for default creation of arrays in a message. + TestRecursiveMessageWithRepeatedField *message = + [TestRecursiveMessageWithRepeatedField message]; + TestRecursiveMessageWithRepeatedField *message2 = + [TestRecursiveMessageWithRepeatedField message]; + + // Simply accessing the array should not make any fields visible. + XCTAssertNotNil(message.a.a.iArray); + XCTAssertFalse([message hasA]); + XCTAssertFalse([message.a hasA]); + XCTAssertNotNil(message2.a.a.strArray); + XCTAssertFalse([message2 hasA]); + XCTAssertFalse([message2.a hasA]); + + // But adding an element to the array should. + [message.a.a.iArray addValue:42]; + XCTAssertTrue([message hasA]); + XCTAssertTrue([message.a hasA]); + XCTAssertEqual([message.a.a.iArray count], (NSUInteger)1); + [message2.a.a.strArray addObject:@"foo"]; + XCTAssertTrue([message2 hasA]); + XCTAssertTrue([message2.a hasA]); + XCTAssertEqual([message2.a.a.strArray count], (NSUInteger)1); +} + +- (void)testAutocreatedArrayShared { + // Multiple objects pointing to the same array. + TestRecursiveMessageWithRepeatedField *message1a = + [TestRecursiveMessageWithRepeatedField message]; + TestRecursiveMessageWithRepeatedField *message1b = + [TestRecursiveMessageWithRepeatedField message]; + message1a.a.iArray = message1b.a.iArray; + XCTAssertTrue([message1a hasA]); + XCTAssertFalse([message1b hasA]); + [message1a.a.iArray addValue:1]; + XCTAssertTrue([message1a hasA]); + XCTAssertTrue([message1b hasA]); + XCTAssertEqual(message1a.a.iArray, message1b.a.iArray); + + TestRecursiveMessageWithRepeatedField *message2a = + [TestRecursiveMessageWithRepeatedField message]; + TestRecursiveMessageWithRepeatedField *message2b = + [TestRecursiveMessageWithRepeatedField message]; + message2a.a.strArray = message2b.a.strArray; + XCTAssertTrue([message2a hasA]); + XCTAssertFalse([message2b hasA]); + [message2a.a.strArray addObject:@"bar"]; + XCTAssertTrue([message2a hasA]); + XCTAssertTrue([message2b hasA]); + XCTAssertEqual(message2a.a.strArray, message2b.a.strArray); +} + +- (void)testAutocreatedArrayCopy { + // Copy should not copy autocreated arrays. + TestAllTypes *message = [TestAllTypes message]; + XCTAssertNotNil(message.repeatedStringArray); + XCTAssertNotNil(message.repeatedInt32Array); + TestAllTypes *message2 = [[message copy] autorelease]; + // Pointer conparisions. + XCTAssertNotEqual(message.repeatedStringArray, message2.repeatedStringArray); + XCTAssertNotEqual(message.repeatedInt32Array, message2.repeatedInt32Array); + + // Mutable copy should copy empty arrays that were explicitly set (end up + // with different objects that are equal). + TestAllTypes *message3 = [TestAllTypes message]; + message3.repeatedInt32Array = [GPBInt32Array arrayWithValue:42]; + message3.repeatedStringArray = [NSMutableArray arrayWithObject:@"wee"]; + XCTAssertNotNil(message.repeatedInt32Array); + XCTAssertNotNil(message.repeatedStringArray); + TestAllTypes *message4 = [message3 copy]; + XCTAssertNotEqual(message3.repeatedInt32Array, message4.repeatedInt32Array); + XCTAssertEqualObjects(message3.repeatedInt32Array, + message4.repeatedInt32Array); + XCTAssertNotEqual(message3.repeatedStringArray, message4.repeatedStringArray); + XCTAssertEqualObjects(message3.repeatedStringArray, + message4.repeatedStringArray); +} + +- (void)testAutocreatedArrayRetain { + // Should be able to retain autocreated array while the creator is dealloced. + TestAllTypes *message = [TestAllTypes message]; + + @autoreleasepool { + TestAllTypes *message2 = [TestAllTypes message]; + message.repeatedInt32Array = message2.repeatedInt32Array; + message.repeatedStringArray = message2.repeatedStringArray; + // Pointer conparision + XCTAssertEqual(message.repeatedInt32Array->_autocreator, message2); + XCTAssertTrue([message.repeatedStringArray + isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertEqual( + ((GPBAutocreatedArray *)message.repeatedStringArray)->_autocreator, + message2); + } + + XCTAssertNil(message.repeatedInt32Array->_autocreator); + XCTAssertTrue( + [message.repeatedStringArray isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertNil( + ((GPBAutocreatedArray *)message.repeatedStringArray)->_autocreator); +} + +- (void)testSetNilAutocreatedArray { + // Setting array to nil should cause it to lose its delegate. + TestAllTypes *message = [TestAllTypes message]; + GPBInt32Array *repeatedInt32Array = [message.repeatedInt32Array retain]; + GPBAutocreatedArray *repeatedStringArray = + (GPBAutocreatedArray *)[message.repeatedStringArray retain]; + XCTAssertTrue([repeatedStringArray isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertEqual(repeatedInt32Array->_autocreator, message); + XCTAssertEqual(repeatedStringArray->_autocreator, message); + message.repeatedInt32Array = nil; + message.repeatedStringArray = nil; + XCTAssertNil(repeatedInt32Array->_autocreator); + XCTAssertNil(repeatedStringArray->_autocreator); + [repeatedInt32Array release]; + [repeatedStringArray release]; +} + +- (void)testReplaceAutocreatedArray { + // Replacing array should orphan the old one and cause its creator to become + // visible. + { + TestRecursiveMessageWithRepeatedField *message = + [TestRecursiveMessageWithRepeatedField message]; + XCTAssertNotNil(message.a); + XCTAssertNotNil(message.a.iArray); + XCTAssertFalse([message hasA]); + GPBInt32Array *iArray = [message.a.iArray retain]; + XCTAssertEqual(iArray->_autocreator, message.a); // Pointer comparision + message.a.iArray = [GPBInt32Array arrayWithValue:1]; + XCTAssertTrue([message hasA]); + XCTAssertNotEqual(message.a.iArray, iArray); // Pointer comparision + XCTAssertNil(iArray->_autocreator); + [iArray release]; + } + + { + TestRecursiveMessageWithRepeatedField *message = + [TestRecursiveMessageWithRepeatedField message]; + XCTAssertNotNil(message.a); + XCTAssertNotNil(message.a.strArray); + XCTAssertFalse([message hasA]); + GPBAutocreatedArray *strArray = + (GPBAutocreatedArray *)[message.a.strArray retain]; + XCTAssertTrue([strArray isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertEqual(strArray->_autocreator, message.a); // Pointer comparision + message.a.strArray = [NSMutableArray arrayWithObject:@"foo"]; + XCTAssertTrue([message hasA]); + XCTAssertNotEqual(message.a.strArray, strArray); // Pointer comparision + XCTAssertNil(strArray->_autocreator); + [strArray release]; + } +} + +- (void)testSetAutocreatedArrayToSelf { + // Setting array to itself should cause it to become visible. + { + TestRecursiveMessageWithRepeatedField *message = + [TestRecursiveMessageWithRepeatedField message]; + XCTAssertNotNil(message.a); + XCTAssertNotNil(message.a.iArray); + XCTAssertFalse([message hasA]); + message.a.iArray = message.a.iArray; + XCTAssertTrue([message hasA]); + XCTAssertNil(message.a.iArray->_autocreator); + } + + { + TestRecursiveMessageWithRepeatedField *message = + [TestRecursiveMessageWithRepeatedField message]; + XCTAssertNotNil(message.a); + XCTAssertNotNil(message.a.strArray); + XCTAssertFalse([message hasA]); + message.a.strArray = message.a.strArray; + XCTAssertTrue([message hasA]); + XCTAssertTrue([message.a.strArray isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertNil(((GPBAutocreatedArray *)message.a.strArray)->_autocreator); + } +} + +- (void)testAutocreatedArrayRemoveAllValues { + // Calling removeAllValues on autocreated array should not cause it to be + // visible. + TestRecursiveMessageWithRepeatedField *message = + [TestRecursiveMessageWithRepeatedField message]; + [message.a.iArray removeAll]; + XCTAssertFalse([message hasA]); + [message.a.strArray removeAllObjects]; + XCTAssertFalse([message hasA]); +} + +- (void)testExtensionAccessors { + TestAllExtensions *message = [TestAllExtensions message]; + [self setAllExtensions:message repeatedCount:kGPBDefaultRepeatCount]; + [self assertAllExtensionsSet:message repeatedCount:kGPBDefaultRepeatCount]; +} + +- (void)testExtensionRepeatedSetters { + TestAllExtensions *message = [TestAllExtensions message]; + [self setAllExtensions:message repeatedCount:kGPBDefaultRepeatCount]; + [self modifyRepeatedExtensions:message]; + [self assertRepeatedExtensionsModified:message + repeatedCount:kGPBDefaultRepeatCount]; +} + +- (void)testExtensionDefaults { + [self assertExtensionsClear:[TestAllExtensions message]]; +} + +- (void)testExtensionIsEquals { + TestAllExtensions *message = [TestAllExtensions message]; + [self setAllExtensions:message repeatedCount:kGPBDefaultRepeatCount]; + [self modifyRepeatedExtensions:message]; + TestAllExtensions *message2 = [TestAllExtensions message]; + [self setAllExtensions:message2 repeatedCount:kGPBDefaultRepeatCount]; + XCTAssertFalse([message isEqual:message2]); + message2 = [TestAllExtensions message]; + [self setAllExtensions:message2 repeatedCount:kGPBDefaultRepeatCount]; + [self modifyRepeatedExtensions:message2]; + XCTAssertEqualObjects(message, message2); +} + +- (void)testExtensionsMergeFrom { + TestAllExtensions *message = [TestAllExtensions message]; + [self setAllExtensions:message repeatedCount:kGPBDefaultRepeatCount]; + [self modifyRepeatedExtensions:message]; + + message = [TestAllExtensions message]; + [self setAllExtensions:message repeatedCount:kGPBDefaultRepeatCount]; + TestAllExtensions *message2 = [TestAllExtensions message]; + [self modifyRepeatedExtensions:message2]; + [message2 mergeFrom:message]; + + XCTAssertEqualObjects(message, message2); +} + +- (void)testDefaultingExtensionMessages { + TestAllExtensions *message = [TestAllExtensions message]; + + // Initially they should all not have values. + + XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]); + XCTAssertFalse( + [message hasExtension:[UnittestRoot optionalNestedMessageExtension]]); + XCTAssertFalse( + [message hasExtension:[UnittestRoot optionalForeignMessageExtension]]); + XCTAssertFalse( + [message hasExtension:[UnittestRoot optionalImportMessageExtension]]); + XCTAssertFalse([message + hasExtension:[UnittestRoot optionalPublicImportMessageExtension]]); + XCTAssertFalse( + [message hasExtension:[UnittestRoot optionalLazyMessageExtension]]); + + // They should auto create something when fetched. + + TestAllTypes_OptionalGroup *optionalGroup = + [message getExtension:[UnittestRoot optionalGroupExtension]]; + TestAllTypes_NestedMessage *optionalNestedMessage = + [message getExtension:[UnittestRoot optionalNestedMessageExtension]]; + ForeignMessage *optionalForeignMessage = + [message getExtension:[UnittestRoot optionalForeignMessageExtension]]; + ImportMessage *optionalImportMessage = + [message getExtension:[UnittestRoot optionalImportMessageExtension]]; + PublicImportMessage *optionalPublicImportMessage = [message + getExtension:[UnittestRoot optionalPublicImportMessageExtension]]; + TestAllTypes_NestedMessage *optionalLazyMessage = + [message getExtension:[UnittestRoot optionalLazyMessageExtension]]; + + XCTAssertNotNil(optionalGroup); + XCTAssertNotNil(optionalNestedMessage); + XCTAssertNotNil(optionalForeignMessage); + XCTAssertNotNil(optionalImportMessage); + XCTAssertNotNil(optionalPublicImportMessage); + XCTAssertNotNil(optionalLazyMessage); + + // Although it auto-created empty messages, it should not show that it has + // them. + + XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalNestedMessageExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalForeignMessageExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalImportMessageExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalPublicImportMessageExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalLazyMessageExtension]]); + + // And they set that value back in to the message since the value created was + // mutable (so a second fetch should give the same object). + + XCTAssertEqual([message getExtension:[UnittestRoot optionalGroupExtension]], + optionalGroup); + XCTAssertEqual( + [message getExtension:[UnittestRoot optionalNestedMessageExtension]], + optionalNestedMessage); + XCTAssertEqual( + [message getExtension:[UnittestRoot optionalForeignMessageExtension]], + optionalForeignMessage); + XCTAssertEqual( + [message getExtension:[UnittestRoot optionalImportMessageExtension]], + optionalImportMessage); + XCTAssertEqual( + [message getExtension:[UnittestRoot optionalPublicImportMessageExtension]], + optionalPublicImportMessage); + XCTAssertEqual( + [message getExtension:[UnittestRoot optionalLazyMessageExtension]], + optionalLazyMessage); + + // And the default objects for a second message should be distinct (again, + // since they are mutable, each needs their own copy). + + TestAllExtensions *message2 = [TestAllExtensions message]; + + // Intentionally doing a pointer comparison. + XCTAssertNotEqual( + [message2 getExtension:[UnittestRoot optionalGroupExtension]], + optionalGroup); + XCTAssertNotEqual( + [message2 getExtension:[UnittestRoot optionalNestedMessageExtension]], + optionalNestedMessage); + XCTAssertNotEqual( + [message2 getExtension:[UnittestRoot optionalForeignMessageExtension]], + optionalForeignMessage); + XCTAssertNotEqual( + [message2 getExtension:[UnittestRoot optionalImportMessageExtension]], + optionalImportMessage); + XCTAssertNotEqual( + [message2 getExtension:[UnittestRoot optionalPublicImportMessageExtension]], + optionalPublicImportMessage); + XCTAssertNotEqual( + [message2 getExtension:[UnittestRoot optionalLazyMessageExtension]], + optionalLazyMessage); + + // Clear values, and on next access you get back new submessages. + + [message setExtension:[UnittestRoot optionalGroupExtension] value:nil]; + [message setExtension:[UnittestRoot optionalGroupExtension] value:nil]; + [message setExtension:[UnittestRoot optionalNestedMessageExtension] + value:nil]; + [message setExtension:[UnittestRoot optionalForeignMessageExtension] + value:nil]; + [message setExtension:[UnittestRoot optionalImportMessageExtension] + value:nil]; + [message setExtension:[UnittestRoot optionalPublicImportMessageExtension] + value:nil]; + [message setExtension:[UnittestRoot optionalLazyMessageExtension] value:nil]; + + XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]); + XCTAssertFalse( + [message hasExtension:[UnittestRoot optionalNestedMessageExtension]]); + XCTAssertFalse( + [message hasExtension:[UnittestRoot optionalForeignMessageExtension]]); + XCTAssertFalse( + [message hasExtension:[UnittestRoot optionalImportMessageExtension]]); + XCTAssertFalse([message + hasExtension:[UnittestRoot optionalPublicImportMessageExtension]]); + XCTAssertFalse( + [message hasExtension:[UnittestRoot optionalLazyMessageExtension]]); + + XCTAssertEqual([message getExtension:[UnittestRoot optionalGroupExtension]], + optionalGroup); + XCTAssertEqual( + [message getExtension:[UnittestRoot optionalNestedMessageExtension]], + optionalNestedMessage); + XCTAssertEqual( + [message getExtension:[UnittestRoot optionalForeignMessageExtension]], + optionalForeignMessage); + XCTAssertEqual( + [message getExtension:[UnittestRoot optionalImportMessageExtension]], + optionalImportMessage); + XCTAssertEqual( + [message + getExtension:[UnittestRoot optionalPublicImportMessageExtension]], + optionalPublicImportMessage); + XCTAssertEqual( + [message getExtension:[UnittestRoot optionalLazyMessageExtension]], + optionalLazyMessage); +} + +- (void)testMultiplePointersToAutocreatedExtension { + // 2 objects point to the same auto-created extension. One should "has" it. + // The other should not. + TestAllExtensions *message = [TestAllExtensions message]; + TestAllExtensions *message2 = [TestAllExtensions message]; + GPBExtensionField *extension = [UnittestRoot optionalGroupExtension]; + [message setExtension:extension value:[message2 getExtension:extension]]; + XCTAssertEqual([message getExtension:extension], + [message2 getExtension:extension]); + XCTAssertFalse([message2 hasExtension:extension]); + XCTAssertTrue([message hasExtension:extension]); + + TestAllTypes_OptionalGroup *extensionValue = + [message2 getExtension:extension]; + extensionValue.a = 1; + XCTAssertTrue([message2 hasExtension:extension]); + XCTAssertTrue([message hasExtension:extension]); +} + +- (void)testCopyWithAutocreatedExtension { + // Mutable copy shouldn't copy autocreated extensions. + TestAllExtensions *message = [TestAllExtensions message]; + GPBExtensionField *optionalGroupExtension = + [UnittestRoot optionalGroupExtension]; + GPBExtensionField *optionalNestedMessageExtesion = + [UnittestRoot optionalNestedMessageExtension]; + TestAllTypes_OptionalGroup *optionalGroup = + [message getExtension:optionalGroupExtension]; + optionalGroup.a = 42; + XCTAssertNotNil(optionalGroup); + XCTAssertNotNil([message getExtension:optionalNestedMessageExtesion]); + XCTAssertTrue([message hasExtension:optionalGroupExtension]); + XCTAssertFalse([message hasExtension:optionalNestedMessageExtesion]); + + TestAllExtensions *message2 = [[message copy] autorelease]; + + // message2 should end up with its own copy of the optional group. + XCTAssertTrue([message2 hasExtension:optionalGroupExtension]); + XCTAssertEqualObjects([message getExtension:optionalGroupExtension], + [message2 getExtension:optionalGroupExtension]); + // Intentionally doing a pointer comparison. + XCTAssertNotEqual([message getExtension:optionalGroupExtension], + [message2 getExtension:optionalGroupExtension]); + + XCTAssertFalse([message2 hasExtension:optionalNestedMessageExtesion]); + // Intentionally doing a pointer comparison (auto creation should be + // different) + XCTAssertNotEqual([message getExtension:optionalNestedMessageExtesion], + [message2 getExtension:optionalNestedMessageExtesion]); +} + +- (void)testClearMessageAutocreatedExtension { + // Call clear should cause it to recreate its autocreated extensions. + TestAllExtensions *message = [TestAllExtensions message]; + GPBExtensionField *optionalGroupExtension = + [UnittestRoot optionalGroupExtension]; + TestAllTypes_OptionalGroup *optionalGroup = + [[message getExtension:optionalGroupExtension] retain]; + [message clear]; + TestAllTypes_OptionalGroup *optionalGroupNew = + [message getExtension:optionalGroupExtension]; + + // Intentionally doing a pointer comparison. + XCTAssertNotEqual(optionalGroup, optionalGroupNew); + [optionalGroup release]; +} + +- (void)testRetainAutocreatedExtension { + // Should be able to retain autocreated extension while the creator is + // dealloced. + TestAllExtensions *message = [TestAllExtensions message]; + GPBExtensionField *optionalGroupExtension = + [UnittestRoot optionalGroupExtension]; + + @autoreleasepool { + TestAllExtensions *message2 = [TestAllExtensions message]; + [message setExtension:optionalGroupExtension + value:[message2 getExtension:optionalGroupExtension]]; + XCTAssertTrue(GPBWasMessageAutocreatedBy( + [message getExtension:optionalGroupExtension], message2)); + } + + XCTAssertFalse(GPBWasMessageAutocreatedBy( + [message getExtension:optionalGroupExtension], message)); +} + +- (void)testClearAutocreatedExtension { + // Clearing autocreated extension should NOT cause it to lose its creator. + TestAllExtensions *message = [TestAllExtensions message]; + GPBExtensionField *optionalGroupExtension = + [UnittestRoot optionalGroupExtension]; + TestAllTypes_OptionalGroup *optionalGroup = + [[message getExtension:optionalGroupExtension] retain]; + [message clearExtension:optionalGroupExtension]; + TestAllTypes_OptionalGroup *optionalGroupNew = + [message getExtension:optionalGroupExtension]; + XCTAssertEqual(optionalGroup, optionalGroupNew); + XCTAssertFalse([message hasExtension:optionalGroupExtension]); + [optionalGroup release]; + + // Clearing autocreated extension should not cause its creator to become + // visible + GPBExtensionField *recursiveExtension = [UnittestObjcRoot recursiveExtension]; + TestAllExtensions *message_lvl2 = [message getExtension:recursiveExtension]; + TestAllExtensions *message_lvl3 = + [message_lvl2 getExtension:recursiveExtension]; + [message_lvl3 clearExtension:recursiveExtension]; + XCTAssertFalse([message hasExtension:recursiveExtension]); +} + +- (void)testSetAutocreatedExtensionBecomesVisible { + // Setting an extension should cause the extension to appear to its creator. + // Test this several levels deep. + TestAllExtensions *message = [TestAllExtensions message]; + GPBExtensionField *recursiveExtension = [UnittestObjcRoot recursiveExtension]; + TestAllExtensions *message_lvl2 = [message getExtension:recursiveExtension]; + TestAllExtensions *message_lvl3 = + [message_lvl2 getExtension:recursiveExtension]; + TestAllExtensions *message_lvl4 = + [message_lvl3 getExtension:recursiveExtension]; + XCTAssertFalse([message hasExtension:recursiveExtension]); + XCTAssertFalse([message_lvl2 hasExtension:recursiveExtension]); + XCTAssertFalse([message_lvl3 hasExtension:recursiveExtension]); + XCTAssertFalse([message_lvl4 hasExtension:recursiveExtension]); + [message_lvl4 setExtension:[UnittestRoot optionalInt32Extension] value:@(1)]; + XCTAssertTrue([message hasExtension:recursiveExtension]); + XCTAssertTrue([message_lvl2 hasExtension:recursiveExtension]); + XCTAssertTrue([message_lvl3 hasExtension:recursiveExtension]); + XCTAssertFalse([message_lvl4 hasExtension:recursiveExtension]); + XCTAssertFalse(GPBWasMessageAutocreatedBy(message_lvl4, message_lvl3)); + XCTAssertFalse(GPBWasMessageAutocreatedBy(message_lvl3, message_lvl2)); + XCTAssertFalse(GPBWasMessageAutocreatedBy(message_lvl2, message)); +} + +- (void)testSetAutocreatedExtensionToSelf { + // Setting extension to itself should cause it to become visible. + TestAllExtensions *message = [TestAllExtensions message]; + GPBExtensionField *optionalGroupExtension = + [UnittestRoot optionalGroupExtension]; + XCTAssertNotNil([message getExtension:optionalGroupExtension]); + XCTAssertFalse([message hasExtension:optionalGroupExtension]); + [message setExtension:optionalGroupExtension + value:[message getExtension:optionalGroupExtension]]; + XCTAssertTrue([message hasExtension:optionalGroupExtension]); +} + +- (void)testAutocreatedExtensionMemoryLeaks { + GPBExtensionField *recursiveExtension = [UnittestObjcRoot recursiveExtension]; + + // Test for memory leaks with autocreated extensions. + TestAllExtensions *message; + TestAllExtensions *message_lvl2; + TestAllExtensions *message_lvl3; + TestAllExtensions *message_lvl4; + @autoreleasepool { + message = [[TestAllExtensions alloc] init]; + message_lvl2 = [[message getExtension:recursiveExtension] retain]; + message_lvl3 = [[message_lvl2 getExtension:recursiveExtension] retain]; + message_lvl4 = [[message_lvl3 getExtension:recursiveExtension] retain]; + [message_lvl2 setExtension:[UnittestRoot optionalInt32Extension] + value:@(1)]; + } + + XCTAssertEqual(message.retainCount, (NSUInteger)1); + @autoreleasepool { + [message release]; + } + XCTAssertEqual(message_lvl2.retainCount, (NSUInteger)1); + @autoreleasepool { + [message_lvl2 release]; + } + XCTAssertEqual(message_lvl3.retainCount, (NSUInteger)1); + @autoreleasepool { + [message_lvl3 release]; + } + XCTAssertEqual(message_lvl4.retainCount, (NSUInteger)1); + [message_lvl4 release]; +} + +- (void)testSetExtensionWithAutocreatedValue { + GPBExtensionField *recursiveExtension = [UnittestObjcRoot recursiveExtension]; + + TestAllExtensions *message; + @autoreleasepool { + message = [[TestAllExtensions alloc] init]; + [message getExtension:recursiveExtension]; + } + + // This statements checks that the extension value isn't accidentally + // dealloced when removing it from the autocreated map. + [message setExtension:recursiveExtension + value:[message getExtension:recursiveExtension]]; + XCTAssertTrue([message hasExtension:recursiveExtension]); + [message release]; +} + +- (void)testRecursion { + TestRecursiveMessage *message = [TestRecursiveMessage message]; + XCTAssertNotNil(message.a); + XCTAssertNotNil(message.a.a); + XCTAssertEqual(message.a.a.i, 0); +} + +- (void)testGenerateAndParseUnknownMessage { + GPBUnknownFieldSet *unknowns = + [[[GPBUnknownFieldSet alloc] init] autorelease]; + [unknowns mergeVarintField:123 value:456]; + GPBMessage *message = [GPBMessage message]; + [message setUnknownFields:unknowns]; + NSData *data = [message data]; + GPBMessage *message2 = [GPBMessage parseFromData:data extensionRegistry:nil]; + XCTAssertEqualObjects(message, message2); +} + +- (void)testDelimitedWriteAndParseMultipleMessages { + GPBUnknownFieldSet *unknowns1 = + [[[GPBUnknownFieldSet alloc] init] autorelease]; + [unknowns1 mergeVarintField:123 value:456]; + GPBMessage *message1 = [GPBMessage message]; + [message1 setUnknownFields:unknowns1]; + + GPBUnknownFieldSet *unknowns2 = + [[[GPBUnknownFieldSet alloc] init] autorelease]; + [unknowns2 mergeVarintField:789 value:987]; + [unknowns2 mergeVarintField:654 value:321]; + GPBMessage *message2 = [GPBMessage message]; + [message2 setUnknownFields:unknowns2]; + + NSMutableData *delimitedData = [NSMutableData data]; + [delimitedData appendData:[message1 delimitedData]]; + [delimitedData appendData:[message2 delimitedData]]; + GPBCodedInputStream *input = + [GPBCodedInputStream streamWithData:delimitedData]; + GPBMessage *message3 = [GPBMessage parseDelimitedFromCodedInputStream:input + extensionRegistry:nil]; + GPBMessage *message4 = [GPBMessage parseDelimitedFromCodedInputStream:input + extensionRegistry:nil]; + XCTAssertEqualObjects(message1, message3); + XCTAssertEqualObjects(message2, message4); +} + +- (void)testDuplicateEnums { + XCTAssertEqual(TestEnumWithDupValue_Foo1, TestEnumWithDupValue_Foo2); +} + +- (void)testWeirdDefaults { + ObjcWeirdDefaults *message = [ObjcWeirdDefaults message]; + GPBDescriptor *descriptor = [[message class] descriptor]; + GPBFieldDescriptor *fieldDesc = [descriptor fieldWithName:@"foo"]; + XCTAssertNotNil(fieldDesc); + XCTAssertTrue(fieldDesc.hasDefaultValue); + XCTAssertFalse(message.hasFoo); + XCTAssertEqualObjects(message.foo, @""); + + fieldDesc = [descriptor fieldWithName:@"bar"]; + XCTAssertNotNil(fieldDesc); + XCTAssertTrue(fieldDesc.hasDefaultValue); + XCTAssertFalse(message.hasBar); + XCTAssertEqualObjects(message.bar, GPBEmptyNSData()); +} + +- (void)testEnumDescriptorFromExtensionDescriptor { + GPBExtensionField *extField = [UnittestRoot optionalForeignEnumExtension]; + GPBExtensionDescriptor *extDescriptor = extField.descriptor; + XCTAssertEqual(extDescriptor.type, GPBTypeEnum); + GPBEnumDescriptor *enumDescriptor = extDescriptor.enumDescriptor; + GPBEnumDescriptor *expectedDescriptor = ForeignEnum_EnumDescriptor(); + XCTAssertEqualObjects(enumDescriptor, expectedDescriptor); +} + +- (void)testEnumNaming { + // objectivec_helpers.cc has some interesting cases to deal with in + // EnumValueName/EnumValueShortName. Confirm that things generated as + // expected. + + // This block just has to compile to confirm we got the expected types/names. + // The *_IsValidValue() calls are just there to keep the projects warnings + // flags happy by providing use of the variables/values. + + Foo aFoo = Foo_SerializedSize; + Foo_IsValidValue(aFoo); + aFoo = Foo_Size; + Foo_IsValidValue(aFoo); + + Category_Enum aCat = Category_Enum_Red; + Category_Enum_IsValidValue(aCat); + + Time aTime = Time_Base; + Time_IsValidValue(aTime); + aTime = Time_SomethingElse; + Time_IsValidValue(aTime); + + // This block confirms the names in the decriptors is what we wanted. + + GPBEnumDescriptor *descriptor; + NSString *valueName; + + descriptor = Foo_EnumDescriptor(); + XCTAssertNotNil(descriptor); + XCTAssertEqualObjects(@"Foo", descriptor.name); + valueName = [descriptor enumNameForValue:Foo_SerializedSize]; + XCTAssertEqualObjects(@"Foo_SerializedSize", valueName); + valueName = [descriptor enumNameForValue:Foo_Size]; + XCTAssertEqualObjects(@"Foo_Size", valueName); + + descriptor = Category_Enum_EnumDescriptor(); + XCTAssertNotNil(descriptor); + XCTAssertEqualObjects(@"Category_Enum", descriptor.name); + valueName = [descriptor enumNameForValue:Category_Enum_Red]; + XCTAssertEqualObjects(@"Category_Enum_Red", valueName); + + descriptor = Time_EnumDescriptor(); + XCTAssertNotNil(descriptor); + XCTAssertEqualObjects(@"Time", descriptor.name); + valueName = [descriptor enumNameForValue:Time_Base]; + XCTAssertEqualObjects(@"Time_Base", valueName); + valueName = [descriptor enumNameForValue:Time_SomethingElse]; + XCTAssertEqualObjects(@"Time_SomethingElse", valueName); +} + +- (void)testNegativeEnums { + EnumTestMsg *msg = [EnumTestMsg message]; + + // Defaults + XCTAssertEqual(msg.foo, EnumTestMsg_MyEnum_Zero); + XCTAssertEqual(msg.bar, EnumTestMsg_MyEnum_One); + XCTAssertEqual(msg.baz, EnumTestMsg_MyEnum_NegOne); + // Bounce to wire and back. + EnumTestMsg *msgPrime = [EnumTestMsg parseFromData:[msg data]]; + XCTAssertEqualObjects(msgPrime, msg); + XCTAssertEqual(msgPrime.foo, EnumTestMsg_MyEnum_Zero); + XCTAssertEqual(msgPrime.bar, EnumTestMsg_MyEnum_One); + XCTAssertEqual(msgPrime.baz, EnumTestMsg_MyEnum_NegOne); + + // Other values + msg.bar = EnumTestMsg_MyEnum_Two; + msg.baz = EnumTestMsg_MyEnum_NegTwo; + XCTAssertEqual(msg.bar, EnumTestMsg_MyEnum_Two); + XCTAssertEqual(msg.baz, EnumTestMsg_MyEnum_NegTwo); + // Bounce to wire and back. + msgPrime = [EnumTestMsg parseFromData:[msg data]]; + XCTAssertEqualObjects(msgPrime, msg); + XCTAssertEqual(msgPrime.foo, EnumTestMsg_MyEnum_Zero); + XCTAssertEqual(msgPrime.bar, EnumTestMsg_MyEnum_Two); + XCTAssertEqual(msgPrime.baz, EnumTestMsg_MyEnum_NegTwo); + + // Repeated field (shouldn't ever be an issue since developer has to use the + // right GPBArray methods themselves). + msg.mumbleArray = [GPBEnumArray + arrayWithValidationFunction:EnumTestMsg_MyEnum_IsValidValue]; + [msg.mumbleArray addValue:EnumTestMsg_MyEnum_Zero]; + [msg.mumbleArray addValue:EnumTestMsg_MyEnum_One]; + [msg.mumbleArray addValue:EnumTestMsg_MyEnum_Two]; + [msg.mumbleArray addValue:EnumTestMsg_MyEnum_NegOne]; + [msg.mumbleArray addValue:EnumTestMsg_MyEnum_NegTwo]; + XCTAssertEqual([msg.mumbleArray valueAtIndex:0], EnumTestMsg_MyEnum_Zero); + XCTAssertEqual([msg.mumbleArray valueAtIndex:1], EnumTestMsg_MyEnum_One); + XCTAssertEqual([msg.mumbleArray valueAtIndex:2], EnumTestMsg_MyEnum_Two); + XCTAssertEqual([msg.mumbleArray valueAtIndex:3], EnumTestMsg_MyEnum_NegOne); + XCTAssertEqual([msg.mumbleArray valueAtIndex:4], EnumTestMsg_MyEnum_NegTwo); + // Bounce to wire and back. + msgPrime = [EnumTestMsg parseFromData:[msg data]]; + XCTAssertEqualObjects(msgPrime, msg); + XCTAssertEqual([msgPrime.mumbleArray valueAtIndex:0], + EnumTestMsg_MyEnum_Zero); + XCTAssertEqual([msgPrime.mumbleArray valueAtIndex:1], EnumTestMsg_MyEnum_One); + XCTAssertEqual([msgPrime.mumbleArray valueAtIndex:2], EnumTestMsg_MyEnum_Two); + XCTAssertEqual([msgPrime.mumbleArray valueAtIndex:3], + EnumTestMsg_MyEnum_NegOne); + XCTAssertEqual([msgPrime.mumbleArray valueAtIndex:4], + EnumTestMsg_MyEnum_NegTwo); +} + +- (void)testMutableNameManagling { + // These basically confirm that all the expected name mangling happened by not + // having compile errors. + + // TODO(thomasvl): Write these, see unittest_name_mangling.proto. +} + +@end diff --git a/objectivec/Tests/GPBPerfTests.m b/objectivec/Tests/GPBPerfTests.m new file mode 100644 index 00000000..d09021af --- /dev/null +++ b/objectivec/Tests/GPBPerfTests.m @@ -0,0 +1,306 @@ +// 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. + +#import "GPBTestUtilities.h" +#import "google/protobuf/Unittest.pbobjc.h" +#import "google/protobuf/UnittestObjc.pbobjc.h" + +// +// This file really just uses the unittests framework as a testbed to +// run some simple performance tests. The data can then be used to help +// evaluate changes to the runtime. +// + +static const uint32_t kRepeatedCount = 100; + +@interface PerfTests : GPBTestCase +@end + +@implementation PerfTests + +- (void)setUp { + // A convenient place to put a break point if you want to connect instruments. + [super setUp]; +} + +- (void)testMessagePerformance { + [self measureBlock:^{ + for (int i = 0; i < 200; ++i) { + TestAllTypes* message = [[TestAllTypes alloc] init]; + [self setAllFields:message repeatedCount:kRepeatedCount]; + NSData* rawBytes = [message data]; + [message release]; + message = [[TestAllTypes alloc] initWithData:rawBytes]; + [message release]; + } + }]; +} + +- (void)testExtensionsPerformance { + [self measureBlock:^{ + for (int i = 0; i < 200; ++i) { + TestAllExtensions* message = [[TestAllExtensions alloc] init]; + [self setAllExtensions:message repeatedCount:kRepeatedCount]; + NSData* rawBytes = [message data]; + [message release]; + TestAllExtensions* message2 = + [[TestAllExtensions alloc] initWithData:rawBytes]; + [message2 release]; + } + }]; +} + +- (void)testPackedTypesPerformance { + [self measureBlock:^{ + for (int i = 0; i < 1000; ++i) { + TestPackedTypes* message = [[TestPackedTypes alloc] init]; + [self setPackedFields:message repeatedCount:kRepeatedCount]; + NSData* rawBytes = [message data]; + [message release]; + message = [[TestPackedTypes alloc] initWithData:rawBytes]; + [message release]; + } + }]; +} + +- (void)testPackedExtensionsPerformance { + [self measureBlock:^{ + for (int i = 0; i < 1000; ++i) { + TestPackedExtensions* message = [[TestPackedExtensions alloc] init]; + [self setPackedExtensions:message repeatedCount:kRepeatedCount]; + NSData* rawBytes = [message data]; + [message release]; + TestPackedExtensions* message2 = + [[TestPackedExtensions alloc] initWithData:rawBytes]; + [message2 release]; + } + }]; +} + +- (void)testHas { + TestAllTypes* message = [self allSetRepeatedCount:1]; + [self measureBlock:^{ + for (int i = 0; i < 10000; ++i) { + [message hasOptionalInt32]; + message.hasOptionalInt32 = NO; + [message hasOptionalInt32]; + + [message hasOptionalInt64]; + message.hasOptionalInt64 = NO; + [message hasOptionalInt64]; + + [message hasOptionalUint32]; + message.hasOptionalUint32 = NO; + [message hasOptionalUint32]; + + [message hasOptionalUint64]; + message.hasOptionalUint64 = NO; + [message hasOptionalUint64]; + + [message hasOptionalSint32]; + message.hasOptionalSint32 = NO; + [message hasOptionalSint32]; + + [message hasOptionalSint64]; + message.hasOptionalSint64 = NO; + [message hasOptionalSint64]; + + [message hasOptionalFixed32]; + message.hasOptionalFixed32 = NO; + [message hasOptionalFixed32]; + + [message hasOptionalFixed64]; + message.hasOptionalFixed64 = NO; + [message hasOptionalFixed64]; + + [message hasOptionalSfixed32]; + message.hasOptionalSfixed32 = NO; + [message hasOptionalSfixed32]; + + [message hasOptionalSfixed64]; + message.hasOptionalSfixed64 = NO; + [message hasOptionalSfixed64]; + + [message hasOptionalFloat]; + message.hasOptionalFloat = NO; + [message hasOptionalFloat]; + + [message hasOptionalDouble]; + message.hasOptionalDouble = NO; + [message hasOptionalDouble]; + + [message hasOptionalBool]; + message.hasOptionalBool = NO; + [message hasOptionalBool]; + + [message hasOptionalString]; + message.hasOptionalString = NO; + [message hasOptionalString]; + + [message hasOptionalBytes]; + message.hasOptionalBytes = NO; + [message hasOptionalBytes]; + + [message hasOptionalGroup]; + message.hasOptionalGroup = NO; + [message hasOptionalGroup]; + + [message hasOptionalNestedMessage]; + message.hasOptionalNestedMessage = NO; + [message hasOptionalNestedMessage]; + + [message hasOptionalForeignMessage]; + message.hasOptionalForeignMessage = NO; + [message hasOptionalForeignMessage]; + + [message hasOptionalImportMessage]; + message.hasOptionalImportMessage = NO; + [message hasOptionalImportMessage]; + + [message.optionalGroup hasA]; + message.optionalGroup.hasA = NO; + [message.optionalGroup hasA]; + + [message.optionalNestedMessage hasBb]; + message.optionalNestedMessage.hasBb = NO; + [message.optionalNestedMessage hasBb]; + + [message.optionalForeignMessage hasC]; + message.optionalForeignMessage.hasC = NO; + [message.optionalForeignMessage hasC]; + + [message.optionalImportMessage hasD]; + message.optionalImportMessage.hasD = NO; + [message.optionalImportMessage hasD]; + + [message hasOptionalNestedEnum]; + message.hasOptionalNestedEnum = NO; + [message hasOptionalNestedEnum]; + + [message hasOptionalForeignEnum]; + message.hasOptionalForeignEnum = NO; + [message hasOptionalForeignEnum]; + + [message hasOptionalImportEnum]; + message.hasOptionalImportEnum = NO; + [message hasOptionalImportEnum]; + + [message hasOptionalStringPiece]; + message.hasOptionalStringPiece = NO; + [message hasOptionalStringPiece]; + + [message hasOptionalCord]; + message.hasOptionalCord = NO; + [message hasOptionalCord]; + + [message hasDefaultInt32]; + message.hasDefaultInt32 = NO; + [message hasDefaultInt32]; + + [message hasDefaultInt64]; + message.hasDefaultInt64 = NO; + [message hasDefaultInt64]; + + [message hasDefaultUint32]; + message.hasDefaultUint32 = NO; + [message hasDefaultUint32]; + + [message hasDefaultUint64]; + message.hasDefaultUint64 = NO; + [message hasDefaultUint64]; + + [message hasDefaultSint32]; + message.hasDefaultSint32 = NO; + [message hasDefaultSint32]; + + [message hasDefaultSint64]; + message.hasDefaultSint64 = NO; + [message hasDefaultSint64]; + + [message hasDefaultFixed32]; + message.hasDefaultFixed32 = NO; + [message hasDefaultFixed32]; + + [message hasDefaultFixed64]; + message.hasDefaultFixed64 = NO; + [message hasDefaultFixed64]; + + [message hasDefaultSfixed32]; + message.hasDefaultSfixed32 = NO; + [message hasDefaultSfixed32]; + + [message hasDefaultSfixed64]; + message.hasDefaultSfixed64 = NO; + [message hasDefaultSfixed64]; + + [message hasDefaultFloat]; + message.hasDefaultFloat = NO; + [message hasDefaultFloat]; + + [message hasDefaultDouble]; + message.hasDefaultDouble = NO; + [message hasDefaultDouble]; + + [message hasDefaultBool]; + message.hasDefaultBool = NO; + [message hasDefaultBool]; + + [message hasDefaultString]; + message.hasDefaultString = NO; + [message hasDefaultString]; + + [message hasDefaultBytes]; + message.hasDefaultBytes = NO; + [message hasDefaultBytes]; + + [message hasDefaultNestedEnum]; + message.hasDefaultNestedEnum = NO; + [message hasDefaultNestedEnum]; + + [message hasDefaultForeignEnum]; + message.hasDefaultForeignEnum = NO; + [message hasDefaultForeignEnum]; + + [message hasDefaultImportEnum]; + message.hasDefaultImportEnum = NO; + [message hasDefaultImportEnum]; + + [message hasDefaultStringPiece]; + message.hasDefaultStringPiece = NO; + [message hasDefaultStringPiece]; + + [message hasDefaultCord]; + message.hasDefaultCord = NO; + [message hasDefaultCord]; + } + }]; +} + +@end diff --git a/objectivec/Tests/GPBStringTests.m b/objectivec/Tests/GPBStringTests.m new file mode 100644 index 00000000..30f13775 --- /dev/null +++ b/objectivec/Tests/GPBStringTests.m @@ -0,0 +1,516 @@ +// 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. + +#import <XCTest/XCTest.h> + +#import "GPBCodedInputStream_PackagePrivate.h" + +#ifndef GPBARRAYSIZE +#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0])))) +#endif // GPBARRAYSIZE + +@interface TestClass : NSObject +@property(nonatomic, retain) NSString *foo; +@end + +@implementation TestClass +@synthesize foo; +@end + +@interface GPBStringTests : XCTestCase { + NSMutableArray *nsStrings_; + NSMutableArray *gpbStrings_; +} + +@end + +@implementation GPBStringTests + +- (void)setUp { + [super setUp]; + const char *strings[] = { + "ascii string", + "non-ascii string \xc3\xa9", // e with acute accent + "\xe2\x99\xa1", // White Heart + "mix \xe2\x99\xa4 string", // White Spade + + // Decomposed forms from http://www.unicode.org/reports/tr15/ + // 1.2 Singletons + "\xe2\x84\xa8 = A\xcc\x8a = \xc3\x85", "\xe2\x84\xa6 = \xce\xa9", + + // 1.2 Canonical Composites + "A\xcc\x8a = \xc3\x85", + "o\xcc\x82 = \xc3\xb4", + + // 1.2 Multiple Combining Marks + "s\xcc\xa3\xcc\x87 = \xe1\xb9\xa9", + "\xe1\xb8\x8b\xcc\xa3 = d\xcc\xa3\xcc\x87 = \xe1\xb8\x8d \xcc\x87", + "q\xcc\x87\xcc\xa3 = q\xcc\xa3\xcc\x87", + + // BOM + "\xEF\xBB\xBF String with BOM", + "String with \xEF\xBB\xBF in middle", + "String with end bom \xEF\xBB\xBF", + "\xEF\xBB\xBF\xe2\x99\xa1", // BOM White Heart + "\xEF\xBB\xBF\xEF\xBB\xBF String with Two BOM", + + // Supplementary Plane + "\xf0\x9d\x84\x9e", // MUSICAL SYMBOL G CLEF + + // Tags + "\xf3\xa0\x80\x81", // Language Tag + + // Variation Selectors + "\xf3\xa0\x84\x80", // VARIATION SELECTOR-17 + + // Specials + "\xef\xbb\xbf\xef\xbf\xbd\xef\xbf\xbf", + + // Left To Right/Right To Left + // http://unicode.org/reports/tr9/ + + // Hello! <RTL marker>!Merhaba<LTR marker> + "Hello! \xE2\x80\x8F!\xd9\x85\xd8\xb1\xd8\xad\xd8\xa8\xd8\xa7\xE2\x80\x8E", + + "\xE2\x80\x8E LTR At Start", + "LTR At End\xE2\x80\x8E", + "\xE2\x80\x8F RTL At Start", + "RTL At End\xE2\x80\x8F", + "\xE2\x80\x8E\xE2\x80\x8E Double LTR \xE2\x80\x8E\xE2\x80\x8E", + "\xE2\x80\x8F\xE2\x80\x8F Double RTL \xE2\x80\x8F\xE2\x80\x8F", + "\xE2\x80\x8F\xE2\x80\x8E LTR-RTL LTR-RTL \xE2\x80\x8E\xE2\x80\x8F", + }; + size_t stringsSize = GPBARRAYSIZE(strings); + size_t numberUnicodeStrings = 17375; + nsStrings_ = [[NSMutableArray alloc] + initWithCapacity:stringsSize + numberUnicodeStrings]; + gpbStrings_ = [[NSMutableArray alloc] + initWithCapacity:stringsSize + numberUnicodeStrings]; + for (size_t i = 0; i < stringsSize; ++i) { + size_t length = strlen(strings[i]); + NSString *nsString = [[NSString alloc] initWithBytes:strings[i] + length:length + encoding:NSUTF8StringEncoding]; + [nsStrings_ addObject:nsString]; + [nsString release]; + GPBString *gpbString = GPBCreateGPBStringWithUTF8(strings[i], length); + [gpbStrings_ addObject:gpbString]; + [gpbString release]; + } + + // Generate all UTF8 characters in a variety of strings + // UTF8-1 - 1 Byte UTF 8 chars + int length = 0x7F + 1; + char *buffer = (char *)calloc(length, 1); + for (int i = 0; i < length; ++i) { + buffer[i] = (char)i; + } + NSString *nsString = [[NSString alloc] initWithBytes:buffer + length:length + encoding:NSUTF8StringEncoding]; + [nsStrings_ addObject:nsString]; + [nsString release]; + GPBString *gpbString = GPBCreateGPBStringWithUTF8(buffer, length); + [gpbStrings_ addObject:gpbString]; + [gpbString release]; + + // UTF8-2 - 2 Byte UTF 8 chars + int pointLength = 0xbf - 0x80 + 1; + length = pointLength * 2; + buffer = (char *)calloc(length, 1); + for (int i = 0xc2; i <= 0xdf; ++i) { + char *bufferPtr = buffer; + for (int j = 0x80; j <= 0xbf; ++j) { + (*bufferPtr++) = (char)i; + (*bufferPtr++) = (char)j; + } + nsString = [[NSString alloc] initWithBytes:buffer + length:length + encoding:NSUTF8StringEncoding]; + [nsStrings_ addObject:nsString]; + [nsString release]; + gpbString = GPBCreateGPBStringWithUTF8(buffer, length); + [gpbStrings_ addObject:gpbString]; + [gpbString release]; + } + free(buffer); + + // UTF8-3 - 3 Byte UTF 8 chars + length = pointLength * 3; + buffer = (char *)calloc(length, 1); + for (int i = 0xa0; i <= 0xbf; ++i) { + char *bufferPtr = buffer; + for (int j = 0x80; j <= 0xbf; ++j) { + (*bufferPtr++) = (char)0xE0; + (*bufferPtr++) = (char)i; + (*bufferPtr++) = (char)j; + } + nsString = [[NSString alloc] initWithBytes:buffer + length:length + encoding:NSUTF8StringEncoding]; + [nsStrings_ addObject:nsString]; + [nsString release]; + gpbString = GPBCreateGPBStringWithUTF8(buffer, length); + [gpbStrings_ addObject:gpbString]; + [gpbString release]; + } + for (int i = 0xe1; i <= 0xec; ++i) { + for (int j = 0x80; j <= 0xbf; ++j) { + char *bufferPtr = buffer; + for (int k = 0x80; k <= 0xbf; ++k) { + (*bufferPtr++) = (char)i; + (*bufferPtr++) = (char)j; + (*bufferPtr++) = (char)k; + } + nsString = [[NSString alloc] initWithBytes:buffer + length:length + encoding:NSUTF8StringEncoding]; + [nsStrings_ addObject:nsString]; + [nsString release]; + gpbString = GPBCreateGPBStringWithUTF8(buffer, length); + [gpbStrings_ addObject:gpbString]; + [gpbString release]; + } + } + for (int i = 0x80; i <= 0x9f; ++i) { + char *bufferPtr = buffer; + for (int j = 0x80; j <= 0xbf; ++j) { + (*bufferPtr++) = (char)0xED; + (*bufferPtr++) = (char)i; + (*bufferPtr++) = (char)j; + } + nsString = [[NSString alloc] initWithBytes:buffer + length:length + encoding:NSUTF8StringEncoding]; + [nsStrings_ addObject:nsString]; + [nsString release]; + gpbString = GPBCreateGPBStringWithUTF8(buffer, length); + [gpbStrings_ addObject:gpbString]; + [gpbString release]; + } + for (int i = 0xee; i <= 0xef; ++i) { + for (int j = 0x80; j <= 0xbf; ++j) { + char *bufferPtr = buffer; + for (int k = 0x80; k <= 0xbf; ++k) { + (*bufferPtr++) = (char)i; + (*bufferPtr++) = (char)j; + (*bufferPtr++) = (char)k; + } + nsString = [[NSString alloc] initWithBytes:buffer + length:length + encoding:NSUTF8StringEncoding]; + [nsStrings_ addObject:nsString]; + [nsString release]; + gpbString = GPBCreateGPBStringWithUTF8(buffer, length); + [gpbStrings_ addObject:gpbString]; + [gpbString release]; + } + } + free(buffer); + + // UTF8-4 - 4 Byte UTF 8 chars + length = pointLength * 4; + buffer = (char *)calloc(length, 1); + for (int i = 0x90; i <= 0xbf; ++i) { + for (int j = 0x80; j <= 0xbf; ++j) { + char *bufferPtr = buffer; + for (int k = 0x80; k <= 0xbf; ++k) { + (*bufferPtr++) = (char)0xF0; + (*bufferPtr++) = (char)i; + (*bufferPtr++) = (char)j; + (*bufferPtr++) = (char)k; + } + nsString = [[NSString alloc] initWithBytes:buffer + length:length + encoding:NSUTF8StringEncoding]; + [nsStrings_ addObject:nsString]; + [nsString release]; + gpbString = GPBCreateGPBStringWithUTF8(buffer, length); + [gpbStrings_ addObject:gpbString]; + [gpbString release]; + } + } + for (int i = 0xf1; i <= 0xf3; ++i) { + for (int j = 0x80; j <= 0xbf; ++j) { + for (int k = 0x80; k <= 0xbf; ++k) { + char *bufferPtr = buffer; + for (int m = 0x80; m <= 0xbf; ++m) { + (*bufferPtr++) = (char)i; + (*bufferPtr++) = (char)j; + (*bufferPtr++) = (char)k; + (*bufferPtr++) = (char)m; + } + nsString = [[NSString alloc] initWithBytes:buffer + length:length + encoding:NSUTF8StringEncoding]; + [nsStrings_ addObject:nsString]; + [nsString release]; + gpbString = GPBCreateGPBStringWithUTF8(buffer, length); + [gpbStrings_ addObject:gpbString]; + [gpbString release]; + } + } + } + for (int i = 0x80; i <= 0x8f; ++i) { + for (int j = 0x80; j <= 0xbf; ++j) { + char *bufferPtr = buffer; + for (int k = 0x80; k <= 0xbf; ++k) { + (*bufferPtr++) = (char)0xF4; + (*bufferPtr++) = (char)i; + (*bufferPtr++) = (char)j; + (*bufferPtr++) = (char)k; + } + nsString = [[NSString alloc] initWithBytes:buffer + length:length + encoding:NSUTF8StringEncoding]; + [nsStrings_ addObject:nsString]; + [nsString release]; + gpbString = GPBCreateGPBStringWithUTF8(buffer, length); + [gpbStrings_ addObject:gpbString]; + [gpbString release]; + } + } + free(buffer); +} + +- (void)tearDown { + [nsStrings_ release]; + [gpbStrings_ release]; + [super tearDown]; +} + +- (void)testLength { + size_t i = 0; + for (NSString *nsString in nsStrings_) { + GPBString *gpbString = gpbStrings_[i]; + XCTAssertEqual([nsString length], [gpbString length], @"%@ %@", nsString, + gpbString); + ++i; + } +} + +- (void)testLengthOfBytesUsingEncoding { + NSStringEncoding encodings[] = { + NSUTF8StringEncoding, + NSASCIIStringEncoding, + NSISOLatin1StringEncoding, + NSMacOSRomanStringEncoding, + NSUTF16StringEncoding, + NSUTF32StringEncoding, + }; + + for (size_t j = 0; j < GPBARRAYSIZE(encodings); ++j) { + NSStringEncoding testEncoding = encodings[j]; + size_t i = 0; + for (NSString *nsString in nsStrings_) { + GPBString *gpbString = gpbStrings_[i]; + XCTAssertEqual([nsString lengthOfBytesUsingEncoding:testEncoding], + [gpbString lengthOfBytesUsingEncoding:testEncoding], + @"%@ %@", nsString, gpbString); + ++i; + } + } +} + +- (void)testHash { + size_t i = 0; + for (NSString *nsString in nsStrings_) { + GPBString *gpbString = gpbStrings_[i]; + XCTAssertEqual([nsString hash], [gpbString hash], @"%@ %@", nsString, + gpbString); + ++i; + } +} + +- (void)testEquality { + size_t i = 0; + for (NSString *nsString in nsStrings_) { + GPBString *gpbString = gpbStrings_[i]; + XCTAssertEqualObjects(nsString, gpbString); + ++i; + } +} + +- (void)testCharacterAtIndex { + size_t i = 0; + for (NSString *nsString in nsStrings_) { + GPBString *gpbString = gpbStrings_[i]; + NSUInteger length = [nsString length]; + for (size_t j = 0; j < length; ++j) { + unichar nsChar = [nsString characterAtIndex:j]; + unichar pbChar = [gpbString characterAtIndex:j]; + XCTAssertEqual(nsChar, pbChar, @"%@ %@ %zu", nsString, gpbString, j); + } + ++i; + } +} + +- (void)testCopy { + size_t i = 0; + for (NSString *nsString in nsStrings_) { + GPBString *gpbString = [[gpbStrings_[i] copy] autorelease]; + XCTAssertEqualObjects(nsString, gpbString); + ++i; + } +} + +- (void)testMutableCopy { + size_t i = 0; + for (NSString *nsString in nsStrings_) { + GPBString *gpbString = [[gpbStrings_[i] mutableCopy] autorelease]; + XCTAssertEqualObjects(nsString, gpbString); + ++i; + } +} + +- (void)testGetBytes { + // Do an attempt at a reasonably exhaustive test of get bytes. + // Get bytes with options other than 0 should always fall through to Apple + // code so we don't bother testing that path. + size_t i = 0; + char pbBuffer[256]; + char nsBuffer[256]; + int count = 0; + for (NSString *nsString in nsStrings_) { + GPBString *gpbString = gpbStrings_[i]; + for (int j = 0; j < 100; ++j) { + // [NSString getBytes:maxLength:usedLength:encoding:options:range:remainingRange] + // does not return reliable results if the maxLength argument is 0, + // or range is 0,0. + // Radar 16385183 + NSUInteger length = [nsString length]; + NSUInteger maxBufferCount = (arc4random() % (length + 3)) + 1; + NSUInteger rangeStart = arc4random() % length; + NSUInteger rangeLength = arc4random() % (length - rangeStart); + + NSRange range = NSMakeRange(rangeStart, rangeLength); + + NSStringEncoding encodings[] = { + NSASCIIStringEncoding, + NSUTF8StringEncoding, + NSUTF16StringEncoding, + }; + + for (size_t k = 0; k < GPBARRAYSIZE(encodings); ++k) { + NSStringEncoding encoding = encodings[k]; + NSUInteger pbUsedBufferCount = 0; + NSUInteger nsUsedBufferCount = 0; + NSRange pbLeftOver = NSMakeRange(0, 0); + NSRange nsLeftOver = NSMakeRange(0, 0); + + BOOL pbGotBytes = [gpbString getBytes:pbBuffer + maxLength:maxBufferCount + usedLength:&pbUsedBufferCount + encoding:encoding + options:0 + range:range + remainingRange:&pbLeftOver]; + BOOL nsGotBytes = [nsString getBytes:nsBuffer + maxLength:maxBufferCount + usedLength:&nsUsedBufferCount + encoding:encoding + options:0 + range:range + remainingRange:&nsLeftOver]; + XCTAssertEqual( + (bool)pbGotBytes, (bool)nsGotBytes, + @"PB %d '%@' vs '%@' Encoding:%tu MaxLength: %tu Range: %@ " + @"Used: %tu, %tu LeftOver %@, %@)", + count, gpbString, nsString, encoding, maxBufferCount, + NSStringFromRange(range), pbUsedBufferCount, nsUsedBufferCount, + NSStringFromRange(pbLeftOver), NSStringFromRange(nsLeftOver)); + XCTAssertEqual( + pbUsedBufferCount, nsUsedBufferCount, + @"PB %d '%@' vs '%@' Encoding:%tu MaxLength: %tu Range: %@ " + @"Used: %tu, %tu LeftOver %@, %@)", + count, gpbString, nsString, encoding, maxBufferCount, + NSStringFromRange(range), pbUsedBufferCount, nsUsedBufferCount, + NSStringFromRange(pbLeftOver), NSStringFromRange(nsLeftOver)); + XCTAssertEqual( + pbLeftOver.location, nsLeftOver.location, + @"PB %d '%@' vs '%@' Encoding:%tu MaxLength: %tu Range: %@ " + @"Used: %tu, %tu LeftOver %@, %@)", + count, gpbString, nsString, encoding, maxBufferCount, + NSStringFromRange(range), pbUsedBufferCount, nsUsedBufferCount, + NSStringFromRange(pbLeftOver), NSStringFromRange(nsLeftOver)); + XCTAssertEqual( + pbLeftOver.length, nsLeftOver.length, + @"PB %d '%@' vs '%@' Encoding:%tu MaxLength: %tu Range: %@ " + @"Used: %tu, %tu LeftOver %@, %@)", + count, gpbString, nsString, encoding, maxBufferCount, + NSStringFromRange(range), pbUsedBufferCount, nsUsedBufferCount, + NSStringFromRange(pbLeftOver), NSStringFromRange(nsLeftOver)); + ++count; + } + } + ++i; + } +} + +- (void)testLengthAndGetBytes { + // This test exists as an attempt to ferret out a bug. + // http://b/13516532 + size_t i = 0; + char pbBuffer[256]; + char nsBuffer[256]; + for (NSString *nsString in nsStrings_) { + GPBString *gpbString = gpbStrings_[i++]; + NSUInteger nsLength = + [nsString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + NSUInteger pbLength = + [gpbString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + XCTAssertEqual(nsLength, pbLength, @"%@ %@", nsString, gpbString); + NSUInteger pbUsedBufferCount = 0; + NSUInteger nsUsedBufferCount = 0; + NSRange pbLeftOver = NSMakeRange(0, 0); + NSRange nsLeftOver = NSMakeRange(0, 0); + NSRange range = NSMakeRange(0, [gpbString length]); + BOOL pbGotBytes = [gpbString getBytes:pbBuffer + maxLength:sizeof(pbBuffer) + usedLength:&pbUsedBufferCount + encoding:NSUTF8StringEncoding + options:0 + range:range + remainingRange:&pbLeftOver]; + BOOL nsGotBytes = [nsString getBytes:nsBuffer + maxLength:sizeof(nsBuffer) + usedLength:&nsUsedBufferCount + encoding:NSUTF8StringEncoding + options:0 + range:range + remainingRange:&nsLeftOver]; + XCTAssertTrue(pbGotBytes, @"%@", gpbString); + XCTAssertTrue(nsGotBytes, @"%@", nsString); + XCTAssertEqual(pbUsedBufferCount, pbLength, @"%@", gpbString); + XCTAssertEqual(nsUsedBufferCount, nsLength, @"%@", nsString); + } +} + +@end diff --git a/objectivec/Tests/GPBSwiftTests.swift b/objectivec/Tests/GPBSwiftTests.swift new file mode 100644 index 00000000..e7b6f94c --- /dev/null +++ b/objectivec/Tests/GPBSwiftTests.swift @@ -0,0 +1,405 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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. + +import Foundation +import XCTest + +// Test some usage of the ObjC library from Swift. + +class GPBBridgeTests: XCTestCase { + + func testProto2Basics() { + let msg = Message2() + let msg2 = Message2() + let msg3 = Message2_OptionalGroup() + + msg.optionalInt32 = 100 + msg.optionalString = "abc" + msg.optionalEnum = .Bar + msg2.optionalString = "other" + msg.optionalMessage = msg2 + msg3.a = 200 + msg.optionalGroup = msg3 + msg.repeatedInt32Array.addValue(300) + msg.repeatedInt32Array.addValue(301) + msg.repeatedStringArray.addObject("mno") + msg.repeatedStringArray.addObject("pqr") + msg.repeatedEnumArray.addValue(Message2_Enum.Bar.rawValue) + msg.repeatedEnumArray.addValue(Message2_Enum.Baz.rawValue) + + // Check has*. + XCTAssertTrue(msg.hasOptionalInt32) + XCTAssertTrue(msg.hasOptionalString) + XCTAssertTrue(msg.hasOptionalEnum) + XCTAssertTrue(msg2.hasOptionalString) + XCTAssertTrue(msg.hasOptionalMessage) + XCTAssertTrue(msg3.hasA) + XCTAssertTrue(msg.hasOptionalGroup) + XCTAssertFalse(msg.hasOptionalInt64) + XCTAssertFalse(msg.hasOptionalFloat) + + // Check values. + XCTAssertEqual(msg.optionalInt32, Int32(100)) + XCTAssertEqual(msg.optionalString, "abc") + XCTAssertEqual(msg2.optionalString, "other") + XCTAssertTrue(msg.optionalMessage === msg2) + XCTAssertEqual(msg.optionalEnum, Message2_Enum.Bar) + XCTAssertEqual(msg3.a, Int32(200)) + XCTAssertTrue(msg.optionalGroup === msg3) + XCTAssertEqual(msg.repeatedInt32Array.count, UInt(2)) + XCTAssertEqual(msg.repeatedInt32Array.valueAtIndex(0), Int32(300)) + XCTAssertEqual(msg.repeatedInt32Array.valueAtIndex(1), Int32(301)) + XCTAssertEqual(msg.repeatedStringArray.count, Int(2)) + XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(0) as! String, "mno") + XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(1) as! String, "pqr") + XCTAssertEqual(msg.repeatedEnumArray.count, UInt(2)) + XCTAssertEqual(msg.repeatedEnumArray.valueAtIndex(0), Message2_Enum.Bar.rawValue) + XCTAssertEqual(msg.repeatedEnumArray.valueAtIndex(1), Message2_Enum.Baz.rawValue) + XCTAssertEqual(msg.repeatedInt64Array.count, UInt(0)) + + // Clearing a string with nil. + msg2.optionalString = nil + XCTAssertFalse(msg2.hasOptionalString) + XCTAssertEqual(msg2.optionalString, "") + + // Clearing a message with nil. + msg.optionalGroup = nil + XCTAssertFalse(msg.hasOptionalGroup) + XCTAssertTrue(msg.optionalGroup !== msg3) // New instance + + // Clear. + msg.clear() + XCTAssertFalse(msg.hasOptionalInt32) + XCTAssertFalse(msg.hasOptionalString) + XCTAssertFalse(msg.hasOptionalEnum) + XCTAssertFalse(msg.hasOptionalMessage) + XCTAssertFalse(msg.hasOptionalInt64) + XCTAssertFalse(msg.hasOptionalFloat) + XCTAssertEqual(msg.optionalInt32, Int32(0)) + XCTAssertEqual(msg.optionalString, "") + XCTAssertTrue(msg.optionalMessage !== msg2) // New instance + XCTAssertEqual(msg.optionalEnum, Message2_Enum.Foo) // Default + XCTAssertEqual(msg.repeatedInt32Array.count, UInt(0)) + XCTAssertEqual(msg.repeatedStringArray.count, Int(0)) + XCTAssertEqual(msg.repeatedEnumArray.count, UInt(0)) + } + + func testProto3Basics() { + let msg = Message3() + let msg2 = Message3() + + msg.optionalInt32 = 100 + msg.optionalString = "abc" + msg.optionalEnum = .Bar + msg2.optionalString = "other" + msg.optionalMessage = msg2 + msg.repeatedInt32Array.addValue(300) + msg.repeatedInt32Array.addValue(301) + msg.repeatedStringArray.addObject("mno") + msg.repeatedStringArray.addObject("pqr") + // "proto3" syntax lets enum get unknown values. + msg.repeatedEnumArray.addValue(Message3_Enum.Bar.rawValue) + msg.repeatedEnumArray.addRawValue(666) + SetMessage3_OptionalEnum_RawValue(msg2, 666) + + // Has only exists on for message fields. + XCTAssertTrue(msg.hasOptionalMessage) + XCTAssertFalse(msg2.hasOptionalMessage) + + // Check values. + XCTAssertEqual(msg.optionalInt32, Int32(100)) + XCTAssertEqual(msg.optionalString, "abc") + XCTAssertEqual(msg2.optionalString, "other") + XCTAssertTrue(msg.optionalMessage === msg2) + XCTAssertEqual(msg.optionalEnum, Message3_Enum.Bar) + XCTAssertEqual(msg.repeatedInt32Array.count, UInt(2)) + XCTAssertEqual(msg.repeatedInt32Array.valueAtIndex(0), Int32(300)) + XCTAssertEqual(msg.repeatedInt32Array.valueAtIndex(1), Int32(301)) + XCTAssertEqual(msg.repeatedStringArray.count, Int(2)) + XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(0) as! String, "mno") + XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(1) as! String, "pqr") + XCTAssertEqual(msg.repeatedInt64Array.count, UInt(0)) + XCTAssertEqual(msg.repeatedEnumArray.count, UInt(2)) + XCTAssertEqual(msg.repeatedEnumArray.valueAtIndex(0), Message3_Enum.Bar.rawValue) + XCTAssertEqual(msg.repeatedEnumArray.valueAtIndex(1), Message3_Enum.GPBUnrecognizedEnumeratorValue.rawValue) + XCTAssertEqual(msg.repeatedEnumArray.rawValueAtIndex(1), 666) + XCTAssertEqual(msg2.optionalEnum, Message3_Enum.GPBUnrecognizedEnumeratorValue) + XCTAssertEqual(Message3_OptionalEnum_RawValue(msg2), Int32(666)) + + // Clearing a string with nil. + msg2.optionalString = nil + XCTAssertEqual(msg2.optionalString, "") + + // Clearing a message with nil. + msg.optionalMessage = nil + XCTAssertFalse(msg.hasOptionalMessage) + XCTAssertTrue(msg.optionalMessage !== msg2) // New instance + + // Clear. + msg.clear() + XCTAssertFalse(msg.hasOptionalMessage) + XCTAssertEqual(msg.optionalInt32, Int32(0)) + XCTAssertEqual(msg.optionalString, "") + XCTAssertTrue(msg.optionalMessage !== msg2) // New instance + XCTAssertEqual(msg.optionalEnum, Message3_Enum.Foo) // Default + XCTAssertEqual(msg.repeatedInt32Array.count, UInt(0)) + XCTAssertEqual(msg.repeatedStringArray.count, Int(0)) + XCTAssertEqual(msg.repeatedEnumArray.count, UInt(0)) + msg2.clear() + XCTAssertEqual(msg2.optionalEnum, Message3_Enum.Foo) // Default + XCTAssertEqual(Message3_OptionalEnum_RawValue(msg2), Message3_Enum.Foo.rawValue) + } + + func testAutoCreation() { + let msg = Message2() + + XCTAssertFalse(msg.hasOptionalGroup) + XCTAssertFalse(msg.hasOptionalMessage) + + // Access shouldn't result in has* but should return objects. + let msg2 = msg.optionalGroup + let msg3 = msg.optionalMessage.optionalMessage + let msg4 = msg.optionalMessage + XCTAssertNotNil(msg2) + XCTAssertNotNil(msg3) + XCTAssertFalse(msg.hasOptionalGroup) + XCTAssertFalse(msg.optionalMessage.hasOptionalMessage) + XCTAssertFalse(msg.hasOptionalMessage) + + // Setting things should trigger has* getting set. + msg.optionalGroup.a = 10 + msg.optionalMessage.optionalMessage.optionalInt32 = 100 + XCTAssertTrue(msg.hasOptionalGroup) + XCTAssertTrue(msg.optionalMessage.hasOptionalMessage) + XCTAssertTrue(msg.hasOptionalMessage) + + // And they should be the same pointer as before. + XCTAssertTrue(msg2 === msg.optionalGroup) + XCTAssertTrue(msg3 === msg.optionalMessage.optionalMessage) + XCTAssertTrue(msg4 === msg.optionalMessage) + + // Clear gets us new objects next time around. + msg.clear() + XCTAssertFalse(msg.hasOptionalGroup) + XCTAssertFalse(msg.optionalMessage.hasOptionalMessage) + XCTAssertFalse(msg.hasOptionalMessage) + msg.optionalGroup.a = 20 + msg.optionalMessage.optionalMessage.optionalInt32 = 200 + XCTAssertTrue(msg.hasOptionalGroup) + XCTAssertTrue(msg.optionalMessage.hasOptionalMessage) + XCTAssertTrue(msg.hasOptionalMessage) + XCTAssertTrue(msg2 !== msg.optionalGroup) + XCTAssertTrue(msg3 !== msg.optionalMessage.optionalMessage) + XCTAssertTrue(msg4 !== msg.optionalMessage) + + // Explicit set of a message, means autocreated object doesn't bind. + msg.clear() + let autoCreated = msg.optionalMessage + XCTAssertFalse(msg.hasOptionalMessage) + let msg5 = Message2() + msg5.optionalInt32 = 123 + msg.optionalMessage = msg5 + XCTAssertTrue(msg.hasOptionalMessage) + // Modifing the autocreated doesn't replaced the explicit set one. + autoCreated.optionalInt32 = 456 + XCTAssertTrue(msg.hasOptionalMessage) + XCTAssertTrue(msg.optionalMessage === msg5) + XCTAssertEqual(msg.optionalMessage.optionalInt32, Int32(123)) + } + + func testProto2OneOfSupport() { + let msg = Message2() + + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.GPBUnsetOneOfCase) + XCTAssertEqual(msg.oneofInt32, Int32(100)) // Default + XCTAssertEqual(msg.oneofFloat, Float(110.0)) // Default + XCTAssertEqual(msg.oneofEnum, Message2_Enum.Baz) // Default + let autoCreated = msg.oneofMessage // Default create one. + XCTAssertNotNil(autoCreated) + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.GPBUnsetOneOfCase) + + msg.oneofInt32 = 10 + XCTAssertEqual(msg.oneofInt32, Int32(10)) + XCTAssertEqual(msg.oneofFloat, Float(110.0)) // Default + XCTAssertEqual(msg.oneofEnum, Message2_Enum.Baz) // Default + XCTAssertTrue(msg.oneofMessage === autoCreated) // Still the same + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofInt32) + + msg.oneofFloat = 20.0 + XCTAssertEqual(msg.oneofInt32, Int32(100)) // Default + XCTAssertEqual(msg.oneofFloat, Float(20.0)) + XCTAssertEqual(msg.oneofEnum, Message2_Enum.Baz) // Default + XCTAssertTrue(msg.oneofMessage === autoCreated) // Still the same + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofFloat) + + msg.oneofEnum = .Bar + XCTAssertEqual(msg.oneofInt32, Int32(100)) // Default + XCTAssertEqual(msg.oneofFloat, Float(110.0)) // Default + XCTAssertEqual(msg.oneofEnum, Message2_Enum.Bar) + XCTAssertTrue(msg.oneofMessage === autoCreated) // Still the same + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofEnum) + + // Sets via the autocreated instance. + msg.oneofMessage.optionalInt32 = 200 + XCTAssertEqual(msg.oneofInt32, Int32(100)) // Default + XCTAssertEqual(msg.oneofFloat, Float(110.0)) // Default + XCTAssertEqual(msg.oneofEnum, Message2_Enum.Baz) // Default + XCTAssertTrue(msg.oneofMessage === autoCreated) // Still the same + XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(200)) + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofMessage) + + // Clear the oneof. + Message2_ClearOOneOfCase(msg) + XCTAssertEqual(msg.oneofInt32, Int32(100)) // Default + XCTAssertEqual(msg.oneofFloat, Float(110.0)) // Default + XCTAssertEqual(msg.oneofEnum, Message2_Enum.Baz) // Default + let autoCreated2 = msg.oneofMessage // Default create one + XCTAssertNotNil(autoCreated2) + XCTAssertTrue(autoCreated2 !== autoCreated) // New instance + XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(0)) // Default + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.GPBUnsetOneOfCase) + + msg.oneofInt32 = 10 + XCTAssertEqual(msg.oneofInt32, Int32(10)) + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofInt32) + + // Confirm Message.clear() handles the oneof correctly. + msg.clear() + XCTAssertEqual(msg.oneofInt32, Int32(100)) // Default + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.GPBUnsetOneOfCase) + + // Sets via the autocreated instance. + msg.oneofMessage.optionalInt32 = 300 + XCTAssertTrue(msg.oneofMessage !== autoCreated) // New instance + XCTAssertTrue(msg.oneofMessage !== autoCreated2) // New instance + XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(300)) + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofMessage) + + // Set message to nil clears the oneof. + msg.oneofMessage = nil + XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(0)) // Default + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.GPBUnsetOneOfCase) +} + + func testProto3OneOfSupport() { + let msg = Message3() + + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.GPBUnsetOneOfCase) + XCTAssertEqual(msg.oneofInt32, Int32(0)) // Default + XCTAssertEqual(msg.oneofFloat, Float(0.0)) // Default + XCTAssertEqual(msg.oneofEnum, Message3_Enum.Foo) // Default + let autoCreated = msg.oneofMessage // Default create one. + XCTAssertNotNil(autoCreated) + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.GPBUnsetOneOfCase) + + msg.oneofInt32 = 10 + XCTAssertEqual(msg.oneofInt32, Int32(10)) + XCTAssertEqual(msg.oneofFloat, Float(0.0)) // Default + XCTAssertEqual(msg.oneofEnum, Message3_Enum.Foo) // Default + XCTAssertTrue(msg.oneofMessage === autoCreated) // Still the same + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofInt32) + + msg.oneofFloat = 20.0 + XCTAssertEqual(msg.oneofInt32, Int32(0)) // Default + XCTAssertEqual(msg.oneofFloat, Float(20.0)) + XCTAssertEqual(msg.oneofEnum, Message3_Enum.Foo) // Default + XCTAssertTrue(msg.oneofMessage === autoCreated) // Still the same + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofFloat) + + msg.oneofEnum = .Bar + XCTAssertEqual(msg.oneofInt32, Int32(0)) // Default + XCTAssertEqual(msg.oneofFloat, Float(0.0)) // Default + XCTAssertEqual(msg.oneofEnum, Message3_Enum.Bar) + XCTAssertTrue(msg.oneofMessage === autoCreated) // Still the same + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofEnum) + + // Sets via the autocreated instance. + msg.oneofMessage.optionalInt32 = 200 + XCTAssertEqual(msg.oneofInt32, Int32(0)) // Default + XCTAssertEqual(msg.oneofFloat, Float(0.0)) // Default + XCTAssertEqual(msg.oneofEnum, Message3_Enum.Foo) // Default + XCTAssertTrue(msg.oneofMessage === autoCreated) // Still the same + XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(200)) + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofMessage) + + // Clear the oneof. + Message3_ClearOOneOfCase(msg) + XCTAssertEqual(msg.oneofInt32, Int32(0)) // Default + XCTAssertEqual(msg.oneofFloat, Float(0.0)) // Default + XCTAssertEqual(msg.oneofEnum, Message3_Enum.Foo) // Default + let autoCreated2 = msg.oneofMessage // Default create one + XCTAssertNotNil(autoCreated2) + XCTAssertTrue(autoCreated2 !== autoCreated) // New instance + XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(0)) // Default + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.GPBUnsetOneOfCase) + + msg.oneofInt32 = 10 + XCTAssertEqual(msg.oneofInt32, Int32(10)) + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofInt32) + + // Confirm Message.clear() handles the oneof correctly. + msg.clear() + XCTAssertEqual(msg.oneofInt32, Int32(0)) // Default + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.GPBUnsetOneOfCase) + + // Sets via the autocreated instance. + msg.oneofMessage.optionalInt32 = 300 + XCTAssertTrue(msg.oneofMessage !== autoCreated) // New instance + XCTAssertTrue(msg.oneofMessage !== autoCreated2) // New instance + XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(300)) + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofMessage) + + // Set message to nil clears the oneof. + msg.oneofMessage = nil + XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(0)) // Default + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.GPBUnsetOneOfCase) + } + + func testSerialization() { + let msg = Message2() + + msg.optionalInt32 = 100 + msg.optionalInt64 = 101 + msg.optionalGroup.a = 102 + msg.repeatedStringArray.addObject("abc") + msg.repeatedStringArray.addObject("def") + + let data = msg.data() + + let msg2 = Message2(data: data) + XCTAssertTrue(msg2 !== msg) // New instance + XCTAssertEqual(msg.optionalInt32, Int32(100)) + XCTAssertEqual(msg.optionalInt64, Int64(101)) + XCTAssertEqual(msg.optionalGroup.a, Int32(102)) + XCTAssertEqual(msg.repeatedStringArray.count, Int(2)) + XCTAssertEqual(msg2, msg) + } + +} diff --git a/objectivec/Tests/GPBTestUtilities.h b/objectivec/Tests/GPBTestUtilities.h new file mode 100644 index 00000000..37e30f96 --- /dev/null +++ b/objectivec/Tests/GPBTestUtilities.h @@ -0,0 +1,87 @@ +// 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. + +#import <XCTest/XCTest.h> + +@class TestAllExtensions; +@class TestAllTypes; +@class TestMap; +@class TestPackedTypes; +@class TestPackedExtensions; +@class GPBExtensionRegistry; + +// The number of repetitions of any repeated objects inside of test messages. +extern const uint32_t kGPBDefaultRepeatCount; + +@interface GPBTestCase : XCTestCase + +- (void)setAllFields:(TestAllTypes *)message repeatedCount:(uint32_t)count; +- (void)clearAllFields:(TestAllTypes *)message; +- (void)setAllExtensions:(TestAllExtensions *)message + repeatedCount:(uint32_t)count; +- (void)setPackedFields:(TestPackedTypes *)message + repeatedCount:(uint32_t)count; +- (void)setPackedExtensions:(TestPackedExtensions *)message + repeatedCount:(uint32_t)count; +- (void)setAllMapFields:(TestMap *)message numEntries:(uint32_t)count; + +- (TestAllTypes *)allSetRepeatedCount:(uint32_t)count; +- (TestAllExtensions *)allExtensionsSetRepeatedCount:(uint32_t)count; +- (TestPackedTypes *)packedSetRepeatedCount:(uint32_t)count; +- (TestPackedExtensions *)packedExtensionsSetRepeatedCount:(uint32_t)count; + +- (void)assertAllFieldsSet:(TestAllTypes *)message + repeatedCount:(uint32_t)count; +- (void)assertAllExtensionsSet:(TestAllExtensions *)message + repeatedCount:(uint32_t)count; +- (void)assertRepeatedFieldsModified:(TestAllTypes *)message + repeatedCount:(uint32_t)count; +- (void)assertRepeatedExtensionsModified:(TestAllExtensions *)message + repeatedCount:(uint32_t)count; +- (void)assertExtensionsClear:(TestAllExtensions *)message; +- (void)assertClear:(TestAllTypes *)message; +- (void)assertPackedFieldsSet:(TestPackedTypes *)message + repeatedCount:(uint32_t)count; +- (void)assertPackedExtensionsSet:(TestPackedExtensions *)message + repeatedCount:(uint32_t)count; + +- (void)modifyRepeatedExtensions:(TestAllExtensions *)message; +- (void)modifyRepeatedFields:(TestAllTypes *)message; + +- (GPBExtensionRegistry *)extensionRegistry; + +- (NSData *)getDataFileNamed:(NSString *)name dataToWrite:(NSData *)dataToWrite; + +- (void)assertAllFieldsKVCMatch:(TestAllTypes *)message; +- (void)setAllFieldsViaKVC:(TestAllTypes *)message + repeatedCount:(uint32_t)count; +- (void)assertClearKVC:(TestAllTypes *)message; + +@end diff --git a/objectivec/Tests/GPBTestUtilities.m b/objectivec/Tests/GPBTestUtilities.m new file mode 100644 index 00000000..d664a88a --- /dev/null +++ b/objectivec/Tests/GPBTestUtilities.m @@ -0,0 +1,2350 @@ +// 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. + +#import "GPBTestUtilities.h" + +#import "google/protobuf/MapUnittest.pbobjc.h" +#import "google/protobuf/Unittest.pbobjc.h" + +const uint32_t kGPBDefaultRepeatCount = 2; + +// Small category to easily turn a CString into an NSData. +@interface NSData (GPBTestCase) ++ (NSData *)gpbtu_dataWithCString:(char *)buffer; ++ (instancetype)gpbtu_dataWithEmbeddedNulls; +@end + +@implementation NSData (GPBTestCase) ++ (NSData *)gpbtu_dataWithCString:(char *)buffer { + return [NSData dataWithBytes:buffer length:strlen(buffer)]; +} + ++ (instancetype)gpbtu_dataWithUint32:(uint32_t)value { + return [[[self alloc] initWithUint32_gpbtu:value] autorelease]; +} + +- (instancetype)initWithUint32_gpbtu:(uint32_t)value { + value = CFSwapInt32HostToLittle(value); + return [self initWithBytes:&value length:sizeof(value)]; +} + ++ (instancetype)gpbtu_dataWithEmbeddedNulls { + char bytes[6] = "\1\0\2\3\0\5"; + return [self dataWithBytes:bytes length:sizeof(bytes)]; +} +@end + +@implementation GPBTestCase + +// Return data for name. Optionally (based on #if setting) write out dataToWrite +// to replace that data. Useful for setting golden masters. +- (NSData *)getDataFileNamed:(NSString *)name + dataToWrite:(NSData *)dataToWrite { + NSBundle *bundle = [NSBundle bundleForClass:[self class]]; + NSString *path = [bundle pathForResource:[name stringByDeletingPathExtension] + ofType:[name pathExtension]]; + XCTAssertNotNil(path, @"Unable to find %@", name); + NSData *data = [NSData dataWithContentsOfFile:path]; + XCTAssertNotNil(data, @"Unable to load from %@", path); +#if 0 + // Enable to write out golden master files. + if (!path) { + path = [[bundle resourcePath] stringByAppendingPathComponent:name]; + } + NSError *error = nil; + BOOL wrote = [dataToWrite writeToFile:path options:NSDataWritingAtomic error:&error]; + XCTAssertTrue(wrote, @"Unable to write %@ (%@)", path, error); + NSLog(@"Wrote data file to %@", path); +#else + // Kill off the unused variable warning. + dataToWrite = dataToWrite; +#endif + return data; +} + +// ------------------------------------------------------------------- + +- (void)modifyRepeatedExtensions:(TestAllExtensions *)message { + [message setExtension:[UnittestRoot repeatedInt32Extension] + index:1 + value:@501]; + [message setExtension:[UnittestRoot repeatedInt64Extension] + index:1 + value:@502]; + [message setExtension:[UnittestRoot repeatedUint32Extension] + index:1 + value:@503]; + [message setExtension:[UnittestRoot repeatedUint64Extension] + index:1 + value:@504]; + [message setExtension:[UnittestRoot repeatedSint32Extension] + index:1 + value:@505]; + [message setExtension:[UnittestRoot repeatedSint64Extension] + index:1 + value:@506]; + [message setExtension:[UnittestRoot repeatedFixed32Extension] + index:1 + value:@507]; + [message setExtension:[UnittestRoot repeatedFixed64Extension] + index:1 + value:@508]; + [message setExtension:[UnittestRoot repeatedSfixed32Extension] + index:1 + value:@509]; + [message setExtension:[UnittestRoot repeatedSfixed64Extension] + index:1 + value:@510]; + [message setExtension:[UnittestRoot repeatedFloatExtension] + index:1 + value:@511.0f]; + [message setExtension:[UnittestRoot repeatedDoubleExtension] + index:1 + value:@512.0]; + [message setExtension:[UnittestRoot repeatedBoolExtension] + index:1 + value:@YES]; + [message setExtension:[UnittestRoot repeatedStringExtension] + index:1 + value:@"515"]; + [message setExtension:[UnittestRoot repeatedBytesExtension] + index:1 + value:[NSData gpbtu_dataWithUint32:516]]; + + RepeatedGroup_extension *repeatedGroup = [RepeatedGroup_extension message]; + [repeatedGroup setA:517]; + [message setExtension:[UnittestRoot repeatedGroupExtension] + index:1 + value:repeatedGroup]; + TestAllTypes_NestedMessage *nestedMessage = + [TestAllTypes_NestedMessage message]; + [nestedMessage setBb:518]; + [message setExtension:[UnittestRoot repeatedNestedMessageExtension] + index:1 + value:nestedMessage]; + ForeignMessage *foreignMessage = [ForeignMessage message]; + [foreignMessage setC:519]; + [message setExtension:[UnittestRoot repeatedForeignMessageExtension] + index:1 + value:foreignMessage]; + ImportMessage *importMessage = [ImportMessage message]; + [importMessage setD:520]; + [message setExtension:[UnittestRoot repeatedImportMessageExtension] + index:1 + value:importMessage]; + + [message setExtension:[UnittestRoot repeatedNestedEnumExtension] + index:1 + value:@(TestAllTypes_NestedEnum_Foo)]; + [message setExtension:[UnittestRoot repeatedForeignEnumExtension] + index:1 + value:@(ForeignEnum_ForeignFoo)]; + [message setExtension:[UnittestRoot repeatedImportEnumExtension] + index:1 + value:@(ImportEnum_ImportFoo)]; + + [message setExtension:[UnittestRoot repeatedStringPieceExtension] + index:1 + value:@"524"]; + [message setExtension:[UnittestRoot repeatedCordExtension] + index:1 + value:@"525"]; +} + +- (void)assertAllExtensionsSet:(TestAllExtensions *)message + repeatedCount:(uint32_t)count { + XCTAssertTrue([message hasExtension:[UnittestRoot optionalInt32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalInt64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalUint32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalUint64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalSint32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalSint64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalFixed32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalFixed64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalSfixed32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalSfixed64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalFloatExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalDoubleExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalBoolExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalStringExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalBytesExtension]]); + + XCTAssertTrue([message hasExtension:[UnittestRoot optionalGroupExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalNestedMessageExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalForeignMessageExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalImportMessageExtension]]); + + XCTAssertTrue([[message getExtension:[UnittestRoot optionalGroupExtension]] hasA]); + XCTAssertTrue([[message getExtension:[UnittestRoot optionalNestedMessageExtension]] hasBb]); + XCTAssertTrue([[message getExtension:[UnittestRoot optionalForeignMessageExtension]] hasC]); + XCTAssertTrue([[message getExtension:[UnittestRoot optionalImportMessageExtension]] hasD]); + + XCTAssertTrue([message hasExtension:[UnittestRoot optionalNestedEnumExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalForeignEnumExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalImportEnumExtension]]); + + XCTAssertTrue([message hasExtension:[UnittestRoot optionalStringPieceExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalCordExtension]]); + + XCTAssertTrue([message hasExtension:[UnittestRoot defaultInt32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultInt64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultUint32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultUint64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultSint32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultSint64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultFixed32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultFixed64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultSfixed32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultSfixed64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultFloatExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultDoubleExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultBoolExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultStringExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultBytesExtension]]); + + XCTAssertTrue([message hasExtension:[UnittestRoot defaultNestedEnumExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultForeignEnumExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultImportEnumExtension]]); + + XCTAssertTrue([message hasExtension:[UnittestRoot defaultStringPieceExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultCordExtension]]); + + XCTAssertEqual(101, [[message getExtension:[UnittestRoot optionalInt32Extension]] intValue]); + XCTAssertEqual(102LL, [[message getExtension:[UnittestRoot optionalInt64Extension]] longLongValue]); + XCTAssertEqual(103U, [[message getExtension:[UnittestRoot optionalUint32Extension]] unsignedIntValue]); + XCTAssertEqual(104ULL, [[message getExtension:[UnittestRoot optionalUint64Extension]] unsignedLongLongValue]); + XCTAssertEqual(105, [[message getExtension:[UnittestRoot optionalSint32Extension]] intValue]); + XCTAssertEqual(106LL, [[message getExtension:[UnittestRoot optionalSint64Extension]] longLongValue]); + XCTAssertEqual(107U, [[message getExtension:[UnittestRoot optionalFixed32Extension]] unsignedIntValue]); + XCTAssertEqual(108ULL, [[message getExtension:[UnittestRoot optionalFixed64Extension]] unsignedLongLongValue]); + XCTAssertEqual(109, [[message getExtension:[UnittestRoot optionalSfixed32Extension]] intValue]); + XCTAssertEqual(110LL, [[message getExtension:[UnittestRoot optionalSfixed64Extension]] longLongValue]); + XCTAssertEqualWithAccuracy(111.0f, [[message getExtension:[UnittestRoot optionalFloatExtension]] floatValue], 0.01); + XCTAssertEqualWithAccuracy(112.0, [[message getExtension:[UnittestRoot optionalDoubleExtension]] doubleValue], 0.01); + XCTAssertTrue([[message getExtension:[UnittestRoot optionalBoolExtension]] boolValue]); + XCTAssertEqualObjects(@"115", [message getExtension:[UnittestRoot optionalStringExtension]]); + XCTAssertEqualObjects([NSData gpbtu_dataWithEmbeddedNulls], [message getExtension:[UnittestRoot optionalBytesExtension]]); + + XCTAssertEqual(117, [(TestAllTypes_OptionalGroup*)[message getExtension:[UnittestRoot optionalGroupExtension]] a]); + XCTAssertEqual(118, [(TestAllTypes_NestedMessage*)[message getExtension:[UnittestRoot optionalNestedMessageExtension]] bb]); + XCTAssertEqual(119, [[message getExtension:[UnittestRoot optionalForeignMessageExtension]] c]); + XCTAssertEqual(120, [[message getExtension:[UnittestRoot optionalImportMessageExtension]] d]); + + XCTAssertEqual(TestAllTypes_NestedEnum_Baz, [[message getExtension:[UnittestRoot optionalNestedEnumExtension]] intValue]); + XCTAssertEqual(ForeignEnum_ForeignBaz, [[message getExtension:[UnittestRoot optionalForeignEnumExtension]] intValue]); + XCTAssertEqual(ImportEnum_ImportBaz, [[message getExtension:[UnittestRoot optionalImportEnumExtension]] intValue]); + + XCTAssertEqualObjects(@"124", [message getExtension:[UnittestRoot optionalStringPieceExtension]]); + XCTAssertEqualObjects(@"125", [message getExtension:[UnittestRoot optionalCordExtension]]); + + // ----------------------------------------------------------------- + + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedInt32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedInt64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedUint32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedUint64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSint32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSint64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedFixed32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedFixed64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSfixed32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSfixed64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedFloatExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedDoubleExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedBoolExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedStringExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedBytesExtension]] count]); + + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedGroupExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedNestedMessageExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedForeignMessageExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedImportMessageExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedNestedEnumExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedForeignEnumExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedImportEnumExtension]] count]); + + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedStringPieceExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedCordExtension]] count]); + + for (uint32_t i = 0; i < count; ++i) { + id extension = [message getExtension:[UnittestRoot repeatedInt32Extension]]; + XCTAssertEqual((int)(201 + i * 100), [extension[i] intValue]); + extension = [message getExtension:[UnittestRoot repeatedInt64Extension]]; + XCTAssertEqual(202 + i * 100, [extension[i] longLongValue]); + extension = [message getExtension:[UnittestRoot repeatedUint32Extension]]; + XCTAssertEqual(203 + i * 100, [extension[i] unsignedIntValue]); + extension = [message getExtension:[UnittestRoot repeatedUint64Extension]]; + XCTAssertEqual(204 + i * 100, [extension[i] unsignedLongLongValue]); + extension = [message getExtension:[UnittestRoot repeatedSint32Extension]]; + XCTAssertEqual((int)(205 + i * 100), [extension[i] intValue]); + extension = [message getExtension:[UnittestRoot repeatedSint64Extension]]; + XCTAssertEqual(206 + i * 100, [extension[i] longLongValue]); + extension = [message getExtension:[UnittestRoot repeatedFixed32Extension]]; + XCTAssertEqual(207 + i * 100, [extension[i] unsignedIntValue]); + extension = [message getExtension:[UnittestRoot repeatedFixed64Extension]]; + XCTAssertEqual(208 + i * 100, [extension[i] unsignedLongLongValue]); + extension = [message getExtension:[UnittestRoot repeatedSfixed32Extension]]; + XCTAssertEqual((int)(209 + i * 100), [extension[i] intValue]); + extension = [message getExtension:[UnittestRoot repeatedSfixed64Extension]]; + XCTAssertEqual(210 + i * 100, [extension[i] longLongValue]); + extension = [message getExtension:[UnittestRoot repeatedFloatExtension]]; + XCTAssertEqualWithAccuracy(211 + i * 100, [extension[i] floatValue], 0.01); + extension = [message getExtension:[UnittestRoot repeatedDoubleExtension]]; + XCTAssertEqualWithAccuracy(212 + i * 100, [extension[i] doubleValue], 0.01); + extension = [message getExtension:[UnittestRoot repeatedBoolExtension]]; + XCTAssertEqual((i % 2) ? YES : NO, [extension[i] boolValue]); + + NSString *string = [[NSString alloc] initWithFormat:@"%d", 215 + i * 100]; + extension = [message getExtension:[UnittestRoot repeatedStringExtension]]; + XCTAssertEqualObjects(string, extension[i]); + [string release]; + + NSData *data = [[NSData alloc] initWithUint32_gpbtu:216 + i * 100]; + extension = [message getExtension:[UnittestRoot repeatedBytesExtension]]; + XCTAssertEqualObjects(data, extension[i]); + [data release]; + + extension = [message getExtension:[UnittestRoot repeatedGroupExtension]]; + XCTAssertEqual((int)(217 + i * 100), [(TestAllTypes_OptionalGroup*)extension[i] a]); + extension = [message getExtension:[UnittestRoot repeatedNestedMessageExtension]]; + XCTAssertEqual((int)(218 + i * 100), [(TestAllTypes_NestedMessage*)extension[i] bb]); + extension = [message getExtension:[UnittestRoot repeatedForeignMessageExtension]]; + XCTAssertEqual((int)(219 + i * 100), [extension[i] c]); + extension = [message getExtension:[UnittestRoot repeatedImportMessageExtension]]; + XCTAssertEqual((int)(220 + i * 100), [extension[i] d]); + + extension = [message getExtension:[UnittestRoot repeatedNestedEnumExtension]]; + XCTAssertEqual((i % 2) ? TestAllTypes_NestedEnum_Bar : TestAllTypes_NestedEnum_Baz, [extension[i] intValue]); + extension = [message getExtension:[UnittestRoot repeatedForeignEnumExtension]]; + XCTAssertEqual((i % 2) ? ForeignEnum_ForeignBar : ForeignEnum_ForeignBaz, [extension[i] intValue]); + extension = [message getExtension:[UnittestRoot repeatedImportEnumExtension]]; + XCTAssertEqual((i % 2) ? ImportEnum_ImportBar : ImportEnum_ImportBaz, [extension[i] intValue]); + + string = [[NSString alloc] initWithFormat:@"%d", 224 + i * 100]; + extension = [message getExtension:[UnittestRoot repeatedStringPieceExtension]]; + XCTAssertEqualObjects(string, extension[i]); + [string release]; + + string = [[NSString alloc] initWithFormat:@"%d", 225 + i * 100]; + extension = [message getExtension:[UnittestRoot repeatedCordExtension]]; + XCTAssertEqualObjects(string, extension[i]); + [string release]; + } + + // ----------------------------------------------------------------- + + XCTAssertTrue([message hasExtension:[UnittestRoot defaultInt32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultInt64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultUint32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultUint64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultSint32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultSint64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultFixed32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultFixed64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultSfixed32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultSfixed64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultFloatExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultDoubleExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultBoolExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultStringExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultBytesExtension]]); + + XCTAssertTrue([message hasExtension:[UnittestRoot defaultNestedEnumExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultForeignEnumExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultImportEnumExtension]]); + + XCTAssertTrue([message hasExtension:[UnittestRoot defaultStringPieceExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultCordExtension]]); + + XCTAssertEqual(401, [[message getExtension:[UnittestRoot defaultInt32Extension]] intValue]); + XCTAssertEqual(402LL, [[message getExtension:[UnittestRoot defaultInt64Extension]] longLongValue]); + XCTAssertEqual(403U, [[message getExtension:[UnittestRoot defaultUint32Extension]] unsignedIntValue]); + XCTAssertEqual(404ULL, [[message getExtension:[UnittestRoot defaultUint64Extension]] unsignedLongLongValue]); + XCTAssertEqual(405, [[message getExtension:[UnittestRoot defaultSint32Extension]] intValue]); + XCTAssertEqual(406LL, [[message getExtension:[UnittestRoot defaultSint64Extension]] longLongValue]); + XCTAssertEqual(407U, [[message getExtension:[UnittestRoot defaultFixed32Extension]] unsignedIntValue]); + XCTAssertEqual(408ULL, [[message getExtension:[UnittestRoot defaultFixed64Extension]] unsignedLongLongValue]); + XCTAssertEqual(409, [[message getExtension:[UnittestRoot defaultSfixed32Extension]] intValue]); + XCTAssertEqual(410LL,[[message getExtension:[UnittestRoot defaultSfixed64Extension]] longLongValue]); + XCTAssertEqualWithAccuracy(411.0f, [[message getExtension:[UnittestRoot defaultFloatExtension]] floatValue], 0.01); + XCTAssertEqualWithAccuracy(412.0, [[message getExtension:[UnittestRoot defaultDoubleExtension]] doubleValue], 0.01); + XCTAssertFalse([[message getExtension:[UnittestRoot defaultBoolExtension]] boolValue]); + XCTAssertEqualObjects(@"415", [message getExtension:[UnittestRoot defaultStringExtension]]); + XCTAssertEqualObjects([NSData gpbtu_dataWithUint32:416], [message getExtension:[UnittestRoot defaultBytesExtension]]); + + XCTAssertEqual(TestAllTypes_NestedEnum_Foo, [[message getExtension:[UnittestRoot defaultNestedEnumExtension]] intValue]); + XCTAssertEqual(ForeignEnum_ForeignFoo, [[message getExtension:[UnittestRoot defaultForeignEnumExtension]] intValue]); + XCTAssertEqual(ImportEnum_ImportFoo, [[message getExtension:[UnittestRoot defaultImportEnumExtension]] intValue]); + + XCTAssertEqualObjects(@"424", [message getExtension:[UnittestRoot defaultStringPieceExtension]]); + XCTAssertEqualObjects(@"425", [message getExtension:[UnittestRoot defaultCordExtension]]); +} + +- (void)assertRepeatedExtensionsModified:(TestAllExtensions *)message + repeatedCount:(uint32_t)count { + // ModifyRepeatedFields only sets the second repeated element of each + // field. In addition to verifying this, we also verify that the first + // element and size were *not* modified. + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedInt32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedInt64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedUint32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedUint64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSint32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSint64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedFixed32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedFixed64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSfixed32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSfixed64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedFloatExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedDoubleExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedBoolExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedStringExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedBytesExtension]] count]); + + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedGroupExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedNestedMessageExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedForeignMessageExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedImportMessageExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedNestedEnumExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedForeignEnumExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedImportEnumExtension]] count]); + + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedStringPieceExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedCordExtension]] count]); + + XCTAssertEqual(201,[[message getExtension:[UnittestRoot repeatedInt32Extension]][0] intValue]); + XCTAssertEqual(202LL, [[message getExtension:[UnittestRoot repeatedInt64Extension]][0] longLongValue]); + XCTAssertEqual(203U, [[message getExtension:[UnittestRoot repeatedUint32Extension]][0] unsignedIntValue]); + XCTAssertEqual(204ULL, [[message getExtension:[UnittestRoot repeatedUint64Extension]][0] unsignedLongLongValue]); + XCTAssertEqual(205, [[message getExtension:[UnittestRoot repeatedSint32Extension]][0] intValue]); + XCTAssertEqual(206LL, [[message getExtension:[UnittestRoot repeatedSint64Extension]][0] longLongValue]); + XCTAssertEqual(207U, [[message getExtension:[UnittestRoot repeatedFixed32Extension]][0] unsignedIntValue]); + XCTAssertEqual(208ULL, [[message getExtension:[UnittestRoot repeatedFixed64Extension]][0] unsignedLongLongValue]); + XCTAssertEqual(209, [[message getExtension:[UnittestRoot repeatedSfixed32Extension]][0] intValue]); + XCTAssertEqual(210LL, [[message getExtension:[UnittestRoot repeatedSfixed64Extension]][0] longLongValue]); + XCTAssertEqualWithAccuracy(211.0f, [[message getExtension:[UnittestRoot repeatedFloatExtension]][0] floatValue], 0.01); + XCTAssertEqualWithAccuracy(212.0, [[message getExtension:[UnittestRoot repeatedDoubleExtension]][0] doubleValue], 0.01); + XCTAssertFalse([[message getExtension:[UnittestRoot repeatedBoolExtension]][0] boolValue]); + XCTAssertEqualObjects(@"215", [message getExtension:[UnittestRoot repeatedStringExtension]][0]); + XCTAssertEqualObjects([NSData gpbtu_dataWithUint32:216], [message getExtension:[UnittestRoot repeatedBytesExtension]][0]); + + XCTAssertEqual(217, [(TestAllTypes_OptionalGroup*)[message getExtension:[UnittestRoot repeatedGroupExtension]][0] a]); + XCTAssertEqual(218, [(TestAllTypes_NestedMessage*)[message getExtension:[UnittestRoot repeatedNestedMessageExtension]][0] bb]); + XCTAssertEqual(219, [[message getExtension:[UnittestRoot repeatedForeignMessageExtension]][0] c]); + XCTAssertEqual(220, [[message getExtension:[UnittestRoot repeatedImportMessageExtension]][0] d]); + + XCTAssertEqual(TestAllTypes_NestedEnum_Baz, + [[message getExtension:[UnittestRoot repeatedNestedEnumExtension]][0] intValue]); + XCTAssertEqual(ForeignEnum_ForeignBaz, + [[message getExtension:[UnittestRoot repeatedForeignEnumExtension]][0] intValue]); + XCTAssertEqual(ImportEnum_ImportBaz, + [[message getExtension:[UnittestRoot repeatedImportEnumExtension]][0] intValue]); + + XCTAssertEqualObjects(@"224", [message getExtension:[UnittestRoot repeatedStringPieceExtension]][0]); + XCTAssertEqualObjects(@"225", [message getExtension:[UnittestRoot repeatedCordExtension]][0]); + + // Actually verify the second (modified) elements now. + XCTAssertEqual(501, [[message getExtension:[UnittestRoot repeatedInt32Extension]][1] intValue]); + XCTAssertEqual(502LL, [[message getExtension:[UnittestRoot repeatedInt64Extension]][1] longLongValue]); + XCTAssertEqual(503U, [[message getExtension:[UnittestRoot repeatedUint32Extension]][1] unsignedIntValue]); + XCTAssertEqual(504ULL, [[message getExtension:[UnittestRoot repeatedUint64Extension]][1] unsignedLongLongValue]); + XCTAssertEqual(505, [[message getExtension:[UnittestRoot repeatedSint32Extension]][1] intValue]); + XCTAssertEqual(506LL, [[message getExtension:[UnittestRoot repeatedSint64Extension]][1] longLongValue]); + XCTAssertEqual(507U, [[message getExtension:[UnittestRoot repeatedFixed32Extension]][1] unsignedIntValue]); + XCTAssertEqual(508ULL, [[message getExtension:[UnittestRoot repeatedFixed64Extension]][1] unsignedLongLongValue]); + XCTAssertEqual(509, [[message getExtension:[UnittestRoot repeatedSfixed32Extension]][1] intValue]); + XCTAssertEqual(510LL, [[message getExtension:[UnittestRoot repeatedSfixed64Extension]][1] longLongValue]); + XCTAssertEqualWithAccuracy(511.0f, [[message getExtension:[UnittestRoot repeatedFloatExtension]][1] floatValue], 0.01); + XCTAssertEqualWithAccuracy(512.0, [[message getExtension:[UnittestRoot repeatedDoubleExtension]][1] doubleValue], 0.01); + XCTAssertTrue([[message getExtension:[UnittestRoot repeatedBoolExtension]][1] boolValue]); + XCTAssertEqualObjects(@"515", [message getExtension:[UnittestRoot repeatedStringExtension]][1]); + XCTAssertEqualObjects([NSData gpbtu_dataWithUint32:516], [message getExtension:[UnittestRoot repeatedBytesExtension]][1]); + + XCTAssertEqual(517, [(TestAllTypes_OptionalGroup*)[message getExtension:[UnittestRoot repeatedGroupExtension]][1] a]); + XCTAssertEqual(518, [(TestAllTypes_NestedMessage*)[message getExtension:[UnittestRoot repeatedNestedMessageExtension]][1] bb]); + XCTAssertEqual(519, [[message getExtension:[UnittestRoot repeatedForeignMessageExtension]][1] c]); + XCTAssertEqual(520, [[message getExtension:[UnittestRoot repeatedImportMessageExtension]][1] d]); + + XCTAssertEqual(TestAllTypes_NestedEnum_Foo, + [[message getExtension:[UnittestRoot repeatedNestedEnumExtension]][1] intValue]); + XCTAssertEqual(ForeignEnum_ForeignFoo, + [[message getExtension:[UnittestRoot repeatedForeignEnumExtension]][1] intValue]); + XCTAssertEqual(ImportEnum_ImportFoo, + [[message getExtension:[UnittestRoot repeatedImportEnumExtension]][1] intValue]); + + XCTAssertEqualObjects(@"524", [message getExtension:[UnittestRoot repeatedStringPieceExtension]][1]); + XCTAssertEqualObjects(@"525", [message getExtension:[UnittestRoot repeatedCordExtension]][1]); +} + +// ------------------------------------------------------------------- + +- (void)assertAllFieldsSet:(TestAllTypes *)message + repeatedCount:(uint32_t)count { + XCTAssertTrue(message.hasOptionalInt32); + XCTAssertTrue(message.hasOptionalInt64); + XCTAssertTrue(message.hasOptionalUint32); + XCTAssertTrue(message.hasOptionalUint64); + XCTAssertTrue(message.hasOptionalSint32); + XCTAssertTrue(message.hasOptionalSint64); + XCTAssertTrue(message.hasOptionalFixed32); + XCTAssertTrue(message.hasOptionalFixed64); + XCTAssertTrue(message.hasOptionalSfixed32); + XCTAssertTrue(message.hasOptionalSfixed64); + XCTAssertTrue(message.hasOptionalFloat); + XCTAssertTrue(message.hasOptionalDouble); + XCTAssertTrue(message.hasOptionalBool); + XCTAssertTrue(message.hasOptionalString); + XCTAssertTrue(message.hasOptionalBytes); + + XCTAssertTrue(message.hasOptionalGroup); + XCTAssertTrue(message.hasOptionalNestedMessage); + XCTAssertTrue(message.hasOptionalForeignMessage); + XCTAssertTrue(message.hasOptionalImportMessage); + + XCTAssertTrue(message.optionalGroup.hasA); + XCTAssertTrue(message.optionalNestedMessage.hasBb); + XCTAssertTrue(message.optionalForeignMessage.hasC); + XCTAssertTrue(message.optionalImportMessage.hasD); + + XCTAssertTrue(message.hasOptionalNestedEnum); + XCTAssertTrue(message.hasOptionalForeignEnum); + XCTAssertTrue(message.hasOptionalImportEnum); + + XCTAssertTrue(message.hasOptionalStringPiece); + XCTAssertTrue(message.hasOptionalCord); + + XCTAssertEqual(101, message.optionalInt32); + XCTAssertEqual(102LL, message.optionalInt64); + XCTAssertEqual(103U, message.optionalUint32); + XCTAssertEqual(104ULL, message.optionalUint64); + XCTAssertEqual(105, message.optionalSint32); + XCTAssertEqual(106LL, message.optionalSint64); + XCTAssertEqual(107U, message.optionalFixed32); + XCTAssertEqual(108ULL, message.optionalFixed64); + XCTAssertEqual(109, message.optionalSfixed32); + XCTAssertEqual(110LL, message.optionalSfixed64); + XCTAssertEqualWithAccuracy(111.0f, message.optionalFloat, 0.1); + XCTAssertEqualWithAccuracy(112.0, message.optionalDouble, 0.1); + XCTAssertTrue(message.optionalBool); + XCTAssertEqualObjects(@"115", message.optionalString); + XCTAssertEqualObjects([NSData gpbtu_dataWithEmbeddedNulls], + message.optionalBytes); + + XCTAssertEqual(117, message.optionalGroup.a); + XCTAssertEqual(118, message.optionalNestedMessage.bb); + XCTAssertEqual(119, message.optionalForeignMessage.c); + XCTAssertEqual(120, message.optionalImportMessage.d); + + XCTAssertEqual(TestAllTypes_NestedEnum_Baz, message.optionalNestedEnum); + XCTAssertEqual(ForeignEnum_ForeignBaz, message.optionalForeignEnum); + XCTAssertEqual(ImportEnum_ImportBaz, message.optionalImportEnum); + + XCTAssertEqualObjects(@"124", message.optionalStringPiece); + XCTAssertEqualObjects(@"125", message.optionalCord); + + // ----------------------------------------------------------------- + + XCTAssertEqual(count, message.repeatedInt32Array.count); + XCTAssertEqual(count, message.repeatedInt64Array.count); + XCTAssertEqual(count, message.repeatedUint32Array.count); + XCTAssertEqual(count, message.repeatedUint64Array.count); + XCTAssertEqual(count, message.repeatedSint32Array.count); + XCTAssertEqual(count, message.repeatedSint64Array.count); + XCTAssertEqual(count, message.repeatedFixed32Array.count); + XCTAssertEqual(count, message.repeatedFixed64Array.count); + XCTAssertEqual(count, message.repeatedSfixed32Array.count); + XCTAssertEqual(count, message.repeatedSfixed64Array.count); + XCTAssertEqual(count, message.repeatedFloatArray.count); + XCTAssertEqual(count, message.repeatedDoubleArray.count); + XCTAssertEqual(count, message.repeatedBoolArray.count); + XCTAssertEqual(count, message.repeatedStringArray.count); + XCTAssertEqual(count, message.repeatedBytesArray.count); + + XCTAssertEqual(count, message.repeatedGroupArray.count); + XCTAssertEqual(count, message.repeatedNestedMessageArray.count); + XCTAssertEqual(count, message.repeatedForeignMessageArray.count); + XCTAssertEqual(count, message.repeatedImportMessageArray.count); + XCTAssertEqual(count, message.repeatedNestedEnumArray.count); + XCTAssertEqual(count, message.repeatedForeignEnumArray.count); + XCTAssertEqual(count, message.repeatedImportEnumArray.count); + + XCTAssertEqual(count, message.repeatedStringPieceArray.count); + XCTAssertEqual(count, message.repeatedCordArray.count); + + for (uint32_t i = 0; i < count; ++i) { + XCTAssertEqual((int)(201 + i * 100), + [message.repeatedInt32Array valueAtIndex:i]); + XCTAssertEqual(202 + i * 100, [message.repeatedInt64Array valueAtIndex:i]); + XCTAssertEqual(203 + i * 100, [message.repeatedUint32Array valueAtIndex:i]); + XCTAssertEqual(204 + i * 100, [message.repeatedUint64Array valueAtIndex:i]); + XCTAssertEqual((int)(205 + i * 100), + [message.repeatedSint32Array valueAtIndex:i]); + XCTAssertEqual(206 + i * 100, [message.repeatedSint64Array valueAtIndex:i]); + XCTAssertEqual(207 + i * 100, + [message.repeatedFixed32Array valueAtIndex:i]); + XCTAssertEqual(208 + i * 100, + [message.repeatedFixed64Array valueAtIndex:i]); + XCTAssertEqual((int)(209 + i * 100), + [message.repeatedSfixed32Array valueAtIndex:i]); + XCTAssertEqual(210 + i * 100, + [message.repeatedSfixed64Array valueAtIndex:i]); + XCTAssertEqualWithAccuracy( + 211 + i * 100, [message.repeatedFloatArray valueAtIndex:i], 0.1); + XCTAssertEqualWithAccuracy( + 212 + i * 100, [message.repeatedDoubleArray valueAtIndex:i], 0.1); + XCTAssertEqual((i % 2) ? YES : NO, + [message.repeatedBoolArray valueAtIndex:i]); + + NSString *string = [[NSString alloc] initWithFormat:@"%d", 215 + i * 100]; + XCTAssertEqualObjects(string, message.repeatedStringArray[i]); + [string release]; + + NSData *data = [[NSData alloc] initWithUint32_gpbtu:216 + i * 100]; + XCTAssertEqualObjects(data, message.repeatedBytesArray[i]); + [data release]; + + XCTAssertEqual((int)(217 + i * 100), ((TestAllTypes_RepeatedGroup*)message.repeatedGroupArray[i]).a); + XCTAssertEqual((int)(218 + i * 100), ((TestAllTypes_NestedMessage*)message.repeatedNestedMessageArray[i]).bb); + XCTAssertEqual((int)(219 + i * 100), ((ForeignMessage*)message.repeatedForeignMessageArray[i]).c); + XCTAssertEqual((int)(220 + i * 100), ((ImportMessage*)message.repeatedImportMessageArray[i]).d); + + XCTAssertEqual((i % 2) ? TestAllTypes_NestedEnum_Bar : TestAllTypes_NestedEnum_Baz, [message.repeatedNestedEnumArray valueAtIndex:i]); + XCTAssertEqual((i % 2) ? ForeignEnum_ForeignBar : ForeignEnum_ForeignBaz, [message.repeatedForeignEnumArray valueAtIndex:i]); + XCTAssertEqual((i % 2) ? ImportEnum_ImportBar : ImportEnum_ImportBaz, [message.repeatedImportEnumArray valueAtIndex:i]); + + string = [[NSString alloc] initWithFormat:@"%d", 224 + i * 100]; + XCTAssertEqualObjects(string, message.repeatedStringPieceArray[i]); + [string release]; + + string = [[NSString alloc] initWithFormat:@"%d", 225 + i * 100]; + XCTAssertEqualObjects(string, message.repeatedCordArray[i]); + [string release]; + } + + // ----------------------------------------------------------------- + + XCTAssertTrue(message.hasDefaultInt32); + XCTAssertTrue(message.hasDefaultInt64); + XCTAssertTrue(message.hasDefaultUint32); + XCTAssertTrue(message.hasDefaultUint64); + XCTAssertTrue(message.hasDefaultSint32); + XCTAssertTrue(message.hasDefaultSint64); + XCTAssertTrue(message.hasDefaultFixed32); + XCTAssertTrue(message.hasDefaultFixed64); + XCTAssertTrue(message.hasDefaultSfixed32); + XCTAssertTrue(message.hasDefaultSfixed64); + XCTAssertTrue(message.hasDefaultFloat); + XCTAssertTrue(message.hasDefaultDouble); + XCTAssertTrue(message.hasDefaultBool); + XCTAssertTrue(message.hasDefaultString); + XCTAssertTrue(message.hasDefaultBytes); + + XCTAssertTrue(message.hasDefaultNestedEnum); + XCTAssertTrue(message.hasDefaultForeignEnum); + XCTAssertTrue(message.hasDefaultImportEnum); + + XCTAssertTrue(message.hasDefaultStringPiece); + XCTAssertTrue(message.hasDefaultCord); + + XCTAssertEqual(401, message.defaultInt32); + XCTAssertEqual(402LL, message.defaultInt64); + XCTAssertEqual(403U, message.defaultUint32); + XCTAssertEqual(404ULL, message.defaultUint64); + XCTAssertEqual(405, message.defaultSint32); + XCTAssertEqual(406LL, message.defaultSint64); + XCTAssertEqual(407U, message.defaultFixed32); + XCTAssertEqual(408ULL, message.defaultFixed64); + XCTAssertEqual(409, message.defaultSfixed32); + XCTAssertEqual(410LL, message.defaultSfixed64); + XCTAssertEqualWithAccuracy(411.0f, message.defaultFloat, 0.1); + XCTAssertEqualWithAccuracy(412.0, message.defaultDouble, 0.1); + XCTAssertFalse(message.defaultBool); + XCTAssertEqualObjects(@"415", message.defaultString); + XCTAssertEqualObjects([NSData gpbtu_dataWithUint32:416], + message.defaultBytes); + + XCTAssertEqual(TestAllTypes_NestedEnum_Foo, message.defaultNestedEnum); + XCTAssertEqual(ForeignEnum_ForeignFoo, message.defaultForeignEnum); + XCTAssertEqual(ImportEnum_ImportFoo, message.defaultImportEnum); + + XCTAssertEqualObjects(@"424", message.defaultStringPiece); + XCTAssertEqualObjects(@"425", message.defaultCord); +} + +- (void)setAllFields:(TestAllTypes *)message repeatedCount:(uint32_t)count { + [message setOptionalInt32:101]; + [message setOptionalInt64:102]; + [message setOptionalUint32:103]; + [message setOptionalUint64:104]; + [message setOptionalSint32:105]; + [message setOptionalSint64:106]; + [message setOptionalFixed32:107]; + [message setOptionalFixed64:108]; + [message setOptionalSfixed32:109]; + [message setOptionalSfixed64:110]; + [message setOptionalFloat:111]; + [message setOptionalDouble:112]; + [message setOptionalBool:YES]; + [message setOptionalString:@"115"]; + [message setOptionalBytes:[NSData gpbtu_dataWithEmbeddedNulls]]; + + TestAllTypes_OptionalGroup *allTypes = [TestAllTypes_OptionalGroup message]; + [allTypes setA:117]; + [message setOptionalGroup:allTypes]; + TestAllTypes_NestedMessage *nestedMessage = + [TestAllTypes_NestedMessage message]; + [nestedMessage setBb:118]; + [message setOptionalNestedMessage:nestedMessage]; + ForeignMessage *foreignMessage = [ForeignMessage message]; + [foreignMessage setC:119]; + [message setOptionalForeignMessage:foreignMessage]; + ImportMessage *importMessage = [ImportMessage message]; + [importMessage setD:120]; + [message setOptionalImportMessage:importMessage]; + + [message setOptionalNestedEnum:TestAllTypes_NestedEnum_Baz]; + [message setOptionalForeignEnum:ForeignEnum_ForeignBaz]; + [message setOptionalImportEnum:ImportEnum_ImportBaz]; + + [message setOptionalStringPiece:@"124"]; + [message setOptionalCord:@"125"]; + + // ----------------------------------------------------------------- + + for (uint32_t i = 0; i < count; i++) { + [message.repeatedInt32Array addValue:201 + i * 100]; + [message.repeatedInt64Array addValue:202 + i * 100]; + [message.repeatedUint32Array addValue:203 + i * 100]; + [message.repeatedUint64Array addValue:204 + i * 100]; + [message.repeatedSint32Array addValue:205 + i * 100]; + [message.repeatedSint64Array addValue:206 + i * 100]; + [message.repeatedFixed32Array addValue:207 + i * 100]; + [message.repeatedFixed64Array addValue:208 + i * 100]; + [message.repeatedSfixed32Array addValue:209 + i * 100]; + [message.repeatedSfixed64Array addValue:210 + i * 100]; + [message.repeatedFloatArray addValue:211 + i * 100]; + [message.repeatedDoubleArray addValue:212 + i * 100]; + [message.repeatedBoolArray addValue:(i % 2)]; + NSString *string = [[NSString alloc] initWithFormat:@"%d", 215 + i * 100]; + [message.repeatedStringArray addObject:string]; + [string release]; + + NSData *data = [[NSData alloc] initWithUint32_gpbtu:216 + i * 100]; + [message.repeatedBytesArray addObject:data]; + [data release]; + + TestAllTypes_RepeatedGroup *testAll = + [[TestAllTypes_RepeatedGroup alloc] init]; + [testAll setA:217 + i * 100]; + [message.repeatedGroupArray addObject:testAll]; + [testAll release]; + + nestedMessage = [[TestAllTypes_NestedMessage alloc] init]; + [nestedMessage setBb:218 + i * 100]; + [message.repeatedNestedMessageArray addObject:nestedMessage]; + [nestedMessage release]; + + foreignMessage = [[ForeignMessage alloc] init]; + [foreignMessage setC:219 + i * 100]; + [message.repeatedForeignMessageArray addObject:foreignMessage]; + [foreignMessage release]; + + importMessage = [[ImportMessage alloc] init]; + [importMessage setD:220 + i * 100]; + [message.repeatedImportMessageArray addObject:importMessage]; + [importMessage release]; + + [message.repeatedNestedEnumArray addValue:(i % 2) ? TestAllTypes_NestedEnum_Bar : TestAllTypes_NestedEnum_Baz]; + + [message.repeatedForeignEnumArray addValue:(i % 2) ? ForeignEnum_ForeignBar : ForeignEnum_ForeignBaz]; + [message.repeatedImportEnumArray addValue:(i % 2) ? ImportEnum_ImportBar : ImportEnum_ImportBaz]; + + string = [[NSString alloc] initWithFormat:@"%d", 224 + i * 100]; + [message.repeatedStringPieceArray addObject:string]; + [string release]; + + string = [[NSString alloc] initWithFormat:@"%d", 225 + i * 100]; + [message.repeatedCordArray addObject:string]; + [string release]; + } + // ----------------------------------------------------------------- + + message.defaultInt32 = 401; + message.defaultInt64 = 402; + message.defaultUint32 = 403; + message.defaultUint64 = 404; + message.defaultSint32 = 405; + message.defaultSint64 = 406; + message.defaultFixed32 = 407; + message.defaultFixed64 = 408; + message.defaultSfixed32 = 409; + message.defaultSfixed64 = 410; + message.defaultFloat = 411; + message.defaultDouble = 412; + message.defaultBool = NO; + message.defaultString = @"415"; + message.defaultBytes = [NSData gpbtu_dataWithUint32:416]; + + message.defaultNestedEnum = TestAllTypes_NestedEnum_Foo; + message.defaultForeignEnum = ForeignEnum_ForeignFoo; + message.defaultImportEnum = ImportEnum_ImportFoo; + + message.defaultStringPiece = @"424"; + message.defaultCord = @"425"; +} + +- (void)clearAllFields:(TestAllTypes *)message { + message.hasOptionalInt32 = NO; + message.hasOptionalInt64 = NO; + message.hasOptionalUint32 = NO; + message.hasOptionalUint64 = NO; + message.hasOptionalSint32 = NO; + message.hasOptionalSint64 = NO; + message.hasOptionalFixed32 = NO; + message.hasOptionalFixed64 = NO; + message.hasOptionalSfixed32 = NO; + message.hasOptionalSfixed64 = NO; + message.hasOptionalFloat = NO; + message.hasOptionalDouble = NO; + message.hasOptionalBool = NO; + message.hasOptionalString = NO; + message.hasOptionalBytes = NO; + + message.hasOptionalGroup = NO; + message.hasOptionalNestedMessage = NO; + message.hasOptionalForeignMessage = NO; + message.hasOptionalImportMessage = NO; + + message.hasOptionalNestedEnum = NO; + message.hasOptionalForeignEnum = NO; + message.hasOptionalImportEnum = NO; + + message.hasOptionalStringPiece = NO; + message.hasOptionalCord = NO; + + // ----------------------------------------------------------------- + + [message.repeatedInt32Array removeAll]; + [message.repeatedInt64Array removeAll]; + [message.repeatedUint32Array removeAll]; + [message.repeatedUint64Array removeAll]; + [message.repeatedSint32Array removeAll]; + [message.repeatedSint64Array removeAll]; + [message.repeatedFixed32Array removeAll]; + [message.repeatedFixed64Array removeAll]; + [message.repeatedSfixed32Array removeAll]; + [message.repeatedSfixed64Array removeAll]; + [message.repeatedFloatArray removeAll]; + [message.repeatedDoubleArray removeAll]; + [message.repeatedBoolArray removeAll]; + [message.repeatedStringArray removeAllObjects]; + [message.repeatedBytesArray removeAllObjects]; + + [message.repeatedGroupArray removeAllObjects]; + [message.repeatedNestedMessageArray removeAllObjects]; + [message.repeatedForeignMessageArray removeAllObjects]; + [message.repeatedImportMessageArray removeAllObjects]; + + [message.repeatedNestedEnumArray removeAll]; + [message.repeatedForeignEnumArray removeAll]; + [message.repeatedImportEnumArray removeAll]; + + [message.repeatedStringPieceArray removeAllObjects]; + [message.repeatedCordArray removeAllObjects]; + + // ----------------------------------------------------------------- + + message.hasDefaultInt32 = NO; + message.hasDefaultInt64 = NO; + message.hasDefaultUint32 = NO; + message.hasDefaultUint64 = NO; + message.hasDefaultSint32 = NO; + message.hasDefaultSint64 = NO; + message.hasDefaultFixed32 = NO; + message.hasDefaultFixed64 = NO; + message.hasDefaultSfixed32 = NO; + message.hasDefaultSfixed64 = NO; + message.hasDefaultFloat = NO; + message.hasDefaultDouble = NO; + message.hasDefaultBool = NO; + message.hasDefaultString = NO; + message.hasDefaultBytes = NO; + + message.hasDefaultNestedEnum = NO; + message.hasDefaultForeignEnum = NO; + message.hasDefaultImportEnum = NO; + + message.hasDefaultStringPiece = NO; + message.hasDefaultCord = NO; +} + +- (void)setAllExtensions:(TestAllExtensions *)message + repeatedCount:(uint32_t)count { + [message setExtension:[UnittestRoot optionalInt32Extension] value:@101]; + [message setExtension:[UnittestRoot optionalInt64Extension] value:@102L]; + [message setExtension:[UnittestRoot optionalUint32Extension] value:@103]; + [message setExtension:[UnittestRoot optionalUint64Extension] value:@104L]; + [message setExtension:[UnittestRoot optionalSint32Extension] value:@105]; + [message setExtension:[UnittestRoot optionalSint64Extension] value:@106L]; + [message setExtension:[UnittestRoot optionalFixed32Extension] value:@107]; + [message setExtension:[UnittestRoot optionalFixed64Extension] value:@108L]; + [message setExtension:[UnittestRoot optionalSfixed32Extension] value:@109]; + [message setExtension:[UnittestRoot optionalSfixed64Extension] value:@110L]; + [message setExtension:[UnittestRoot optionalFloatExtension] value:@111.0f]; + [message setExtension:[UnittestRoot optionalDoubleExtension] value:@112.0]; + [message setExtension:[UnittestRoot optionalBoolExtension] value:@YES]; + [message setExtension:[UnittestRoot optionalStringExtension] value:@"115"]; + [message setExtension:[UnittestRoot optionalBytesExtension] + value:[NSData gpbtu_dataWithEmbeddedNulls]]; + + OptionalGroup_extension *optionalGroup = [OptionalGroup_extension message]; + [optionalGroup setA:117]; + [message setExtension:[UnittestRoot optionalGroupExtension] + value:optionalGroup]; + TestAllTypes_NestedMessage *nestedMessage = + [TestAllTypes_NestedMessage message]; + [nestedMessage setBb:118]; + [message setExtension:[UnittestRoot optionalNestedMessageExtension] + value:nestedMessage]; + ForeignMessage *foreignMessage = [ForeignMessage message]; + [foreignMessage setC:119]; + [message setExtension:[UnittestRoot optionalForeignMessageExtension] + value:foreignMessage]; + ImportMessage *importMessage = [ImportMessage message]; + [importMessage setD:120]; + [message setExtension:[UnittestRoot optionalImportMessageExtension] + value:importMessage]; + + [message setExtension:[UnittestRoot optionalNestedEnumExtension] + value:@(TestAllTypes_NestedEnum_Baz)]; + [message setExtension:[UnittestRoot optionalForeignEnumExtension] + value:@(ForeignEnum_ForeignBaz)]; + [message setExtension:[UnittestRoot optionalImportEnumExtension] + value:@(ImportEnum_ImportBaz)]; + + [message setExtension:[UnittestRoot optionalStringPieceExtension] + value:@"124"]; + [message setExtension:[UnittestRoot optionalCordExtension] value:@"125"]; + + for (uint32_t i = 0; i < count; ++i) { + [message addExtension:[UnittestRoot repeatedInt32Extension] + value:@(201 + i * 100)]; + [message addExtension:[UnittestRoot repeatedInt64Extension] + value:@(202 + i * 100)]; + [message addExtension:[UnittestRoot repeatedUint32Extension] + value:@(203 + i * 100)]; + [message addExtension:[UnittestRoot repeatedUint64Extension] + value:@(204 + i * 100)]; + [message addExtension:[UnittestRoot repeatedSint32Extension] + value:@(205 + i * 100)]; + [message addExtension:[UnittestRoot repeatedSint64Extension] + value:@(206 + i * 100)]; + [message addExtension:[UnittestRoot repeatedFixed32Extension] + value:@(207 + i * 100)]; + [message addExtension:[UnittestRoot repeatedFixed64Extension] + value:@(208 + i * 100)]; + [message addExtension:[UnittestRoot repeatedSfixed32Extension] + value:@(209 + i * 100)]; + [message addExtension:[UnittestRoot repeatedSfixed64Extension] + value:@(210 + i * 100)]; + [message addExtension:[UnittestRoot repeatedFloatExtension] + value:@(211 + i * 100)]; + [message addExtension:[UnittestRoot repeatedDoubleExtension] + value:@(212 + i * 100)]; + [message addExtension:[UnittestRoot repeatedBoolExtension] + value:@((i % 2) ? YES : NO)]; + NSString *string = [[NSString alloc] initWithFormat:@"%d", 215 + i * 100]; + [message addExtension:[UnittestRoot repeatedStringExtension] value:string]; + [string release]; + NSData *data = [[NSData alloc] initWithUint32_gpbtu:216 + i * 100]; + [message addExtension:[UnittestRoot repeatedBytesExtension] value:data]; + [data release]; + + RepeatedGroup_extension *repeatedGroup = + [[RepeatedGroup_extension alloc] init]; + [repeatedGroup setA:217 + i * 100]; + [message addExtension:[UnittestRoot repeatedGroupExtension] + value:repeatedGroup]; + [repeatedGroup release]; + nestedMessage = [[TestAllTypes_NestedMessage alloc] init]; + [nestedMessage setBb:218 + i * 100]; + [message addExtension:[UnittestRoot repeatedNestedMessageExtension] + value:nestedMessage]; + [nestedMessage release]; + foreignMessage = [[ForeignMessage alloc] init]; + [foreignMessage setC:219 + i * 100]; + [message addExtension:[UnittestRoot repeatedForeignMessageExtension] + value:foreignMessage]; + [foreignMessage release]; + importMessage = [[ImportMessage alloc] init]; + [importMessage setD:220 + i * 100]; + [message addExtension:[UnittestRoot repeatedImportMessageExtension] + value:importMessage]; + [importMessage release]; + [message addExtension:[UnittestRoot repeatedNestedEnumExtension] + value:@((i % 2) ? TestAllTypes_NestedEnum_Bar + : TestAllTypes_NestedEnum_Baz)]; + [message addExtension:[UnittestRoot repeatedForeignEnumExtension] + value:@((i % 2) ? ForeignEnum_ForeignBar + : ForeignEnum_ForeignBaz)]; + [message + addExtension:[UnittestRoot repeatedImportEnumExtension] + value:@((i % 2) ? ImportEnum_ImportBar : ImportEnum_ImportBaz)]; + + string = [[NSString alloc] initWithFormat:@"%d", 224 + i * 100]; + [message addExtension:[UnittestRoot repeatedStringPieceExtension] + value:string]; + [string release]; + + string = [[NSString alloc] initWithFormat:@"%d", 225 + i * 100]; + [message addExtension:[UnittestRoot repeatedCordExtension] value:string]; + [string release]; + } + + // ----------------------------------------------------------------- + + [message setExtension:[UnittestRoot defaultInt32Extension] value:@401]; + [message setExtension:[UnittestRoot defaultInt64Extension] value:@402L]; + [message setExtension:[UnittestRoot defaultUint32Extension] value:@403]; + [message setExtension:[UnittestRoot defaultUint64Extension] value:@404L]; + [message setExtension:[UnittestRoot defaultSint32Extension] value:@405]; + [message setExtension:[UnittestRoot defaultSint64Extension] value:@406L]; + [message setExtension:[UnittestRoot defaultFixed32Extension] value:@407]; + [message setExtension:[UnittestRoot defaultFixed64Extension] value:@408L]; + [message setExtension:[UnittestRoot defaultSfixed32Extension] value:@409]; + [message setExtension:[UnittestRoot defaultSfixed64Extension] value:@410L]; + [message setExtension:[UnittestRoot defaultFloatExtension] value:@411.0f]; + [message setExtension:[UnittestRoot defaultDoubleExtension] value:@412.0]; + [message setExtension:[UnittestRoot defaultBoolExtension] value:@NO]; + [message setExtension:[UnittestRoot defaultStringExtension] value:@"415"]; + [message setExtension:[UnittestRoot defaultBytesExtension] + value:[NSData gpbtu_dataWithUint32:416]]; + + [message setExtension:[UnittestRoot defaultNestedEnumExtension] + value:@(TestAllTypes_NestedEnum_Foo)]; + [message setExtension:[UnittestRoot defaultForeignEnumExtension] + value:@(ForeignEnum_ForeignFoo)]; + [message setExtension:[UnittestRoot defaultImportEnumExtension] + value:@(ImportEnum_ImportFoo)]; + + [message setExtension:[UnittestRoot defaultStringPieceExtension] + value:@"424"]; + [message setExtension:[UnittestRoot defaultCordExtension] value:@"425"]; +} + +- (void)setAllMapFields:(TestMap *)message numEntries:(uint32_t)count { + message.mapInt32Int32 = [GPBInt32Int32Dictionary dictionary]; + message.mapInt64Int64 = [GPBInt64Int64Dictionary dictionary]; + message.mapUint32Uint32 = [GPBUInt32UInt32Dictionary dictionary]; + message.mapUint64Uint64 = [GPBUInt64UInt64Dictionary dictionary]; + message.mapSint32Sint32 = [GPBInt32Int32Dictionary dictionary]; + message.mapSint64Sint64 = [GPBInt64Int64Dictionary dictionary]; + message.mapFixed32Fixed32 = [GPBUInt32UInt32Dictionary dictionary]; + message.mapFixed64Fixed64 = [GPBUInt64UInt64Dictionary dictionary]; + message.mapSfixed32Sfixed32 = [GPBInt32Int32Dictionary dictionary]; + message.mapSfixed64Sfixed64 = [GPBInt64Int64Dictionary dictionary]; + message.mapInt32Float = [GPBInt32FloatDictionary dictionary]; + message.mapInt32Double = [GPBInt32DoubleDictionary dictionary]; + message.mapBoolBool = [GPBBoolBoolDictionary dictionary]; + message.mapStringString = [NSMutableDictionary dictionary]; + message.mapInt32Bytes = [GPBInt32ObjectDictionary dictionary]; + message.mapInt32Enum = [GPBInt32EnumDictionary + dictionaryWithValidationFunction:MapEnum_IsValidValue]; + message.mapInt32ForeignMessage = [GPBInt32ObjectDictionary dictionary]; + + for (uint32_t i = 0; i < count; i++) { + [message.mapInt32Int32 setValue:(i + 1) forKey:100 + i * 100]; + [message.mapInt64Int64 setValue:(i + 1) forKey:101 + i * 100]; + [message.mapUint32Uint32 setValue:(i + 1) forKey:102 + i * 100]; + [message.mapUint64Uint64 setValue:(i + 1) forKey:103 + i * 100]; + [message.mapSint32Sint32 setValue:(i + 1) forKey:104 + i * 100]; + [message.mapSint64Sint64 setValue:(i + 1) forKey:105 + i * 100]; + [message.mapFixed32Fixed32 setValue:(i + 1) forKey:106 + i * 100]; + [message.mapFixed64Fixed64 setValue:(i + 1) forKey:107 + i * 100]; + [message.mapSfixed32Sfixed32 setValue:(i + 1) forKey:108 + i * 100]; + [message.mapSfixed64Sfixed64 setValue:(i + 1) forKey:109 + i * 100]; + [message.mapInt32Float setValue:(i + 1) forKey:110 + i * 100]; + [message.mapInt32Double setValue:(i + 1) forKey:111 + i * 100]; + [message.mapBoolBool setValue:((i % 2) == 1) forKey:((i % 2) == 0)]; + + NSString *keyStr = [[NSString alloc] initWithFormat:@"%d", 112 + i * 100]; + NSString *dataStr = [[NSString alloc] initWithFormat:@"%d", i + 1]; + [message.mapStringString setObject:dataStr forKey:keyStr]; + [keyStr release]; + [dataStr release]; + + NSData *data = [[NSData alloc] initWithUint32_gpbtu:i + 1]; + [message.mapInt32Bytes setValue:data forKey:113 + i * 100]; + [data release]; + + [message.mapInt32Enum + setValue:(i % 2) ? MapEnum_MapEnumBar : MapEnum_MapEnumBaz + forKey:114 + i * 100]; + + ForeignMessage *subMsg = [[ForeignMessage alloc] init]; + subMsg.c = i + 1; + [message.mapInt32ForeignMessage setValue:subMsg forKey:115 + i * 100]; + [subMsg release]; + } +} + +- (GPBExtensionRegistry *)extensionRegistry { + return [UnittestRoot extensionRegistry]; +} + +- (TestAllTypes *)allSetRepeatedCount:(uint32_t)count { + TestAllTypes *message = [TestAllTypes message]; + [self setAllFields:message repeatedCount:count]; + return message; +} + +- (TestAllExtensions *)allExtensionsSetRepeatedCount:(uint32_t)count { + TestAllExtensions *message = [TestAllExtensions message]; + [self setAllExtensions:message repeatedCount:count]; + return message; +} + +- (TestPackedTypes *)packedSetRepeatedCount:(uint32_t)count { + TestPackedTypes *message = [TestPackedTypes message]; + [self setPackedFields:message repeatedCount:count]; + return message; +} + +- (TestPackedExtensions *)packedExtensionsSetRepeatedCount:(uint32_t)count { + TestPackedExtensions *message = [TestPackedExtensions message]; + [self setPackedExtensions:message repeatedCount:count]; + return message; +} + +// ------------------------------------------------------------------- + +- (void)assertClear:(TestAllTypes *)message { + // hasBlah() should initially be NO for all optional fields. + XCTAssertFalse(message.hasOptionalInt32); + XCTAssertFalse(message.hasOptionalInt64); + XCTAssertFalse(message.hasOptionalUint32); + XCTAssertFalse(message.hasOptionalUint64); + XCTAssertFalse(message.hasOptionalSint32); + XCTAssertFalse(message.hasOptionalSint64); + XCTAssertFalse(message.hasOptionalFixed32); + XCTAssertFalse(message.hasOptionalFixed64); + XCTAssertFalse(message.hasOptionalSfixed32); + XCTAssertFalse(message.hasOptionalSfixed64); + XCTAssertFalse(message.hasOptionalFloat); + XCTAssertFalse(message.hasOptionalDouble); + XCTAssertFalse(message.hasOptionalBool); + XCTAssertFalse(message.hasOptionalString); + XCTAssertFalse(message.hasOptionalBytes); + + XCTAssertFalse(message.hasOptionalGroup); + XCTAssertFalse(message.hasOptionalNestedMessage); + XCTAssertFalse(message.hasOptionalForeignMessage); + XCTAssertFalse(message.hasOptionalImportMessage); + + XCTAssertFalse(message.hasOptionalNestedEnum); + XCTAssertFalse(message.hasOptionalForeignEnum); + XCTAssertFalse(message.hasOptionalImportEnum); + + XCTAssertFalse(message.hasOptionalStringPiece); + XCTAssertFalse(message.hasOptionalCord); + + // Optional fields without defaults are set to zero or something like it. + XCTAssertEqual(0, message.optionalInt32); + XCTAssertEqual(0LL, message.optionalInt64); + XCTAssertEqual(0U, message.optionalUint32); + XCTAssertEqual(0ULL, message.optionalUint64); + XCTAssertEqual(0, message.optionalSint32); + XCTAssertEqual(0LL, message.optionalSint64); + XCTAssertEqual(0U, message.optionalFixed32); + XCTAssertEqual(0ULL, message.optionalFixed64); + XCTAssertEqual(0, message.optionalSfixed32); + XCTAssertEqual(0LL, message.optionalSfixed64); + XCTAssertEqual(0.0f, message.optionalFloat); + XCTAssertEqual(0.0, message.optionalDouble); + XCTAssertFalse(message.optionalBool); + XCTAssertEqualObjects(message.optionalString, @""); + XCTAssertEqualObjects(message.optionalBytes, GPBEmptyNSData()); + + // Embedded messages should also be clear. + XCTAssertFalse(message.hasOptionalGroup); + XCTAssertFalse(message.hasOptionalNestedMessage); + XCTAssertFalse(message.hasOptionalForeignMessage); + XCTAssertFalse(message.hasOptionalImportMessage); + + // Enums without defaults are set to the first value in the enum. + XCTAssertEqual(TestAllTypes_NestedEnum_Foo, message.optionalNestedEnum); + XCTAssertEqual(ForeignEnum_ForeignFoo, message.optionalForeignEnum); + XCTAssertEqual(ImportEnum_ImportFoo, message.optionalImportEnum); + + XCTAssertEqualObjects(message.optionalStringPiece, @""); + XCTAssertEqualObjects(message.optionalCord, @""); + + // Repeated fields are empty. + XCTAssertEqual(0U, message.repeatedInt32Array.count); + XCTAssertEqual(0U, message.repeatedInt64Array.count); + XCTAssertEqual(0U, message.repeatedUint32Array.count); + XCTAssertEqual(0U, message.repeatedUint64Array.count); + XCTAssertEqual(0U, message.repeatedSint32Array.count); + XCTAssertEqual(0U, message.repeatedSint64Array.count); + XCTAssertEqual(0U, message.repeatedFixed32Array.count); + XCTAssertEqual(0U, message.repeatedFixed64Array.count); + XCTAssertEqual(0U, message.repeatedSfixed32Array.count); + XCTAssertEqual(0U, message.repeatedSfixed64Array.count); + XCTAssertEqual(0U, message.repeatedFloatArray.count); + XCTAssertEqual(0U, message.repeatedDoubleArray.count); + XCTAssertEqual(0U, message.repeatedBoolArray.count); + XCTAssertEqual(0U, message.repeatedStringArray.count); + XCTAssertEqual(0U, message.repeatedBytesArray.count); + + XCTAssertEqual(0U, message.repeatedGroupArray.count); + XCTAssertEqual(0U, message.repeatedNestedMessageArray.count); + XCTAssertEqual(0U, message.repeatedForeignMessageArray.count); + XCTAssertEqual(0U, message.repeatedImportMessageArray.count); + XCTAssertEqual(0U, message.repeatedNestedEnumArray.count); + XCTAssertEqual(0U, message.repeatedForeignEnumArray.count); + XCTAssertEqual(0U, message.repeatedImportEnumArray.count); + + XCTAssertEqual(0U, message.repeatedStringPieceArray.count); + XCTAssertEqual(0U, message.repeatedCordArray.count); + + // hasBlah() should also be NO for all default fields. + XCTAssertFalse(message.hasDefaultInt32); + XCTAssertFalse(message.hasDefaultInt64); + XCTAssertFalse(message.hasDefaultUint32); + XCTAssertFalse(message.hasDefaultUint64); + XCTAssertFalse(message.hasDefaultSint32); + XCTAssertFalse(message.hasDefaultSint64); + XCTAssertFalse(message.hasDefaultFixed32); + XCTAssertFalse(message.hasDefaultFixed64); + XCTAssertFalse(message.hasDefaultSfixed32); + XCTAssertFalse(message.hasDefaultSfixed64); + XCTAssertFalse(message.hasDefaultFloat); + XCTAssertFalse(message.hasDefaultDouble); + XCTAssertFalse(message.hasDefaultBool); + XCTAssertFalse(message.hasDefaultString); + XCTAssertFalse(message.hasDefaultBytes); + + XCTAssertFalse(message.hasDefaultNestedEnum); + XCTAssertFalse(message.hasDefaultForeignEnum); + XCTAssertFalse(message.hasDefaultImportEnum); + + XCTAssertFalse(message.hasDefaultStringPiece); + XCTAssertFalse(message.hasDefaultCord); + + // Fields with defaults have their default values (duh). + XCTAssertEqual(41, message.defaultInt32); + XCTAssertEqual(42LL, message.defaultInt64); + XCTAssertEqual(43U, message.defaultUint32); + XCTAssertEqual(44ULL, message.defaultUint64); + XCTAssertEqual(-45, message.defaultSint32); + XCTAssertEqual(46LL, message.defaultSint64); + XCTAssertEqual(47U, message.defaultFixed32); + XCTAssertEqual(48ULL, message.defaultFixed64); + XCTAssertEqual(49, message.defaultSfixed32); + XCTAssertEqual(-50LL, message.defaultSfixed64); + XCTAssertEqualWithAccuracy(51.5f, message.defaultFloat, 0.1); + XCTAssertEqualWithAccuracy(52e3, message.defaultDouble, 0.1); + XCTAssertTrue(message.defaultBool); + XCTAssertEqualObjects(@"hello", message.defaultString); + XCTAssertEqualObjects([NSData gpbtu_dataWithCString:"world"], + message.defaultBytes); + + XCTAssertEqual(TestAllTypes_NestedEnum_Bar, message.defaultNestedEnum); + XCTAssertEqual(ForeignEnum_ForeignBar, message.defaultForeignEnum); + XCTAssertEqual(ImportEnum_ImportBar, message.defaultImportEnum); + + XCTAssertEqualObjects(@"abc", message.defaultStringPiece); + XCTAssertEqualObjects(@"123", message.defaultCord); +} + +- (void)assertExtensionsClear:(TestAllExtensions *)message { + // hasBlah() should initially be NO for all optional fields. + XCTAssertFalse([message hasExtension:[UnittestRoot optionalInt32Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalInt64Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalUint32Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalUint64Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalSint32Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalSint64Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalFixed32Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalFixed64Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalSfixed32Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalSfixed64Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalFloatExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalDoubleExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalBoolExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalStringExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalBytesExtension]]); + + XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalNestedMessageExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalForeignMessageExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalImportMessageExtension]]); + + XCTAssertFalse([message hasExtension:[UnittestRoot optionalNestedEnumExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalForeignEnumExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalImportEnumExtension]]); + + XCTAssertFalse([message hasExtension:[UnittestRoot optionalStringPieceExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalCordExtension]]); + + // Optional fields without defaults are set to zero or something like it. + XCTAssertEqual(0, [[message getExtension:[UnittestRoot optionalInt32Extension]] intValue]); + XCTAssertEqual(0LL,[[message getExtension:[UnittestRoot optionalInt64Extension]] longLongValue]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot optionalUint32Extension]] unsignedIntValue]); + XCTAssertEqual(0ULL, [[message getExtension:[UnittestRoot optionalUint64Extension]] unsignedLongLongValue]); + XCTAssertEqual(0, [[message getExtension:[UnittestRoot optionalSint32Extension]] intValue]); + XCTAssertEqual(0LL, [[message getExtension:[UnittestRoot optionalSint64Extension]] longLongValue]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot optionalFixed32Extension]] unsignedIntValue]); + XCTAssertEqual(0ULL, [[message getExtension:[UnittestRoot optionalFixed64Extension]] unsignedLongLongValue]); + XCTAssertEqual(0, [[message getExtension:[UnittestRoot optionalSfixed32Extension]] intValue]); + XCTAssertEqual(0LL, [[message getExtension:[UnittestRoot optionalSfixed64Extension]] longLongValue]); + XCTAssertEqualWithAccuracy(0.0f, [[message getExtension:[UnittestRoot optionalFloatExtension]] floatValue], 0.01); + XCTAssertEqualWithAccuracy(0.0, [[message getExtension:[UnittestRoot optionalDoubleExtension]] doubleValue], 0.01); + XCTAssertFalse([[message getExtension:[UnittestRoot optionalBoolExtension]] boolValue]); + XCTAssertEqualObjects(@"", [message getExtension:[UnittestRoot optionalStringExtension]]); + XCTAssertEqualObjects(GPBEmptyNSData(), [message getExtension:[UnittestRoot optionalBytesExtension]]); + + // Embedded messages should also be clear. + + XCTAssertFalse([[message getExtension:[UnittestRoot optionalGroupExtension]] hasA]); + XCTAssertFalse([[message getExtension:[UnittestRoot optionalNestedMessageExtension]] hasBb]); + XCTAssertFalse([[message getExtension:[UnittestRoot optionalForeignMessageExtension]] hasC]); + XCTAssertFalse([[message getExtension:[UnittestRoot optionalImportMessageExtension]] hasD]); + + XCTAssertEqual(0, [(TestAllTypes_OptionalGroup*)[message getExtension:[UnittestRoot optionalGroupExtension]] a]); + XCTAssertEqual(0, [(TestAllTypes_NestedMessage*)[message getExtension:[UnittestRoot optionalNestedMessageExtension]] bb]); + XCTAssertEqual(0, [[message getExtension:[UnittestRoot optionalForeignMessageExtension]] c]); + XCTAssertEqual(0, [[message getExtension:[UnittestRoot optionalImportMessageExtension]] d]); + + // Enums without defaults are set to the first value in the enum. + XCTAssertEqual(TestAllTypes_NestedEnum_Foo, + [[message getExtension:[UnittestRoot optionalNestedEnumExtension]] intValue]); + XCTAssertEqual(ForeignEnum_ForeignFoo, + [[message getExtension:[UnittestRoot optionalForeignEnumExtension]] intValue]); + XCTAssertEqual(ImportEnum_ImportFoo, + [[message getExtension:[UnittestRoot optionalImportEnumExtension]] intValue]); + + XCTAssertEqualObjects(@"", [message getExtension:[UnittestRoot optionalStringPieceExtension]]); + XCTAssertEqualObjects(@"", [message getExtension:[UnittestRoot optionalCordExtension]]); + + // Repeated fields are empty. + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedInt32Extension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedInt64Extension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedUint32Extension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedUint64Extension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedSint32Extension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedSint64Extension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedFixed32Extension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedFixed64Extension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedSfixed32Extension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedSfixed64Extension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedFloatExtension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedDoubleExtension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedBoolExtension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedStringExtension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedBytesExtension]] count]); + + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedGroupExtension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedNestedMessageExtension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedForeignMessageExtension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedImportMessageExtension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedNestedEnumExtension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedForeignEnumExtension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedImportEnumExtension]] count]); + + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedStringPieceExtension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedCordExtension]] count]); + + // hasBlah() should also be NO for all default fields. + XCTAssertFalse([message hasExtension:[UnittestRoot defaultInt32Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultInt64Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultUint32Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultUint64Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultSint32Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultSint64Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultFixed32Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultFixed64Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultSfixed32Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultSfixed64Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultFloatExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultDoubleExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultBoolExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultStringExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultBytesExtension]]); + + XCTAssertFalse([message hasExtension:[UnittestRoot defaultNestedEnumExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultForeignEnumExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultImportEnumExtension]]); + + XCTAssertFalse([message hasExtension:[UnittestRoot defaultStringPieceExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultCordExtension]]); + + // Fields with defaults have their default values (duh). + XCTAssertEqual( 41, [[message getExtension:[UnittestRoot defaultInt32Extension]] intValue]); + XCTAssertEqual( 42LL, [[message getExtension:[UnittestRoot defaultInt64Extension]] longLongValue]); + XCTAssertEqual( 43U, [[message getExtension:[UnittestRoot defaultUint32Extension]] unsignedIntValue]); + XCTAssertEqual( 44ULL, [[message getExtension:[UnittestRoot defaultUint64Extension]] unsignedLongLongValue]); + XCTAssertEqual(-45, [[message getExtension:[UnittestRoot defaultSint32Extension]] intValue]); + XCTAssertEqual( 46LL, [[message getExtension:[UnittestRoot defaultSint64Extension]] longLongValue]); + XCTAssertEqual( 47, [[message getExtension:[UnittestRoot defaultFixed32Extension]] intValue]); + XCTAssertEqual( 48ULL, [[message getExtension:[UnittestRoot defaultFixed64Extension]] unsignedLongLongValue]); + XCTAssertEqual( 49, [[message getExtension:[UnittestRoot defaultSfixed32Extension]] intValue]); + XCTAssertEqual(-50LL, [[message getExtension:[UnittestRoot defaultSfixed64Extension]] longLongValue]); + XCTAssertEqualWithAccuracy( 51.5f, [[message getExtension:[UnittestRoot defaultFloatExtension]] floatValue], 0.01); + XCTAssertEqualWithAccuracy( 52e3, [[message getExtension:[UnittestRoot defaultDoubleExtension]] doubleValue], 0.01); + XCTAssertTrue([[message getExtension:[UnittestRoot defaultBoolExtension]] boolValue]); + XCTAssertEqualObjects(@"hello", [message getExtension:[UnittestRoot defaultStringExtension]]); + XCTAssertEqualObjects([NSData gpbtu_dataWithCString:"world"], [message getExtension:[UnittestRoot defaultBytesExtension]]); + + XCTAssertEqual(TestAllTypes_NestedEnum_Bar, + [[message getExtension:[UnittestRoot defaultNestedEnumExtension]] intValue]); + XCTAssertEqual(ForeignEnum_ForeignBar, + [[message getExtension:[UnittestRoot defaultForeignEnumExtension]] intValue]); + XCTAssertEqual(ImportEnum_ImportBar, + [[message getExtension:[UnittestRoot defaultImportEnumExtension]] intValue]); + + XCTAssertEqualObjects(@"abc", [message getExtension:[UnittestRoot defaultStringPieceExtension]]); + XCTAssertEqualObjects(@"123", [message getExtension:[UnittestRoot defaultCordExtension]]); +} + +- (void)modifyRepeatedFields:(TestAllTypes *)message { + [message.repeatedInt32Array replaceValueAtIndex:1 withValue:501]; + [message.repeatedInt64Array replaceValueAtIndex:1 withValue:502]; + [message.repeatedUint32Array replaceValueAtIndex:1 withValue:503]; + [message.repeatedUint64Array replaceValueAtIndex:1 withValue:504]; + [message.repeatedSint32Array replaceValueAtIndex:1 withValue:505]; + [message.repeatedSint64Array replaceValueAtIndex:1 withValue:506]; + [message.repeatedFixed32Array replaceValueAtIndex:1 withValue:507]; + [message.repeatedFixed64Array replaceValueAtIndex:1 withValue:508]; + [message.repeatedSfixed32Array replaceValueAtIndex:1 withValue:509]; + [message.repeatedSfixed64Array replaceValueAtIndex:1 withValue:510]; + [message.repeatedFloatArray replaceValueAtIndex:1 withValue:511]; + [message.repeatedDoubleArray replaceValueAtIndex:1 withValue:512]; + [message.repeatedBoolArray replaceValueAtIndex:1 withValue:YES]; + [message.repeatedStringArray replaceObjectAtIndex:1 withObject:@"515"]; + + NSData *data = [[NSData alloc] initWithUint32_gpbtu:516]; + [message.repeatedBytesArray replaceObjectAtIndex:1 withObject:data]; + [data release]; + + TestAllTypes_RepeatedGroup *testAll = + [[TestAllTypes_RepeatedGroup alloc] init]; + [testAll setA:517]; + [message.repeatedGroupArray replaceObjectAtIndex:1 withObject:testAll]; + [testAll release]; + + TestAllTypes_NestedMessage *nestedMessage = + [[TestAllTypes_NestedMessage alloc] init]; + [nestedMessage setBb:518]; + [message.repeatedNestedMessageArray replaceObjectAtIndex:1 + withObject:nestedMessage]; + [nestedMessage release]; + + ForeignMessage *foreignMessage = [[ForeignMessage alloc] init]; + [foreignMessage setC:519]; + [message.repeatedForeignMessageArray replaceObjectAtIndex:1 + withObject:foreignMessage]; + [foreignMessage release]; + + ImportMessage *importMessage = [[ImportMessage alloc] init]; + [importMessage setD:520]; + [message.repeatedImportMessageArray replaceObjectAtIndex:1 + withObject:importMessage]; + [importMessage release]; + + [message.repeatedNestedEnumArray replaceValueAtIndex:1 withValue:TestAllTypes_NestedEnum_Foo]; + [message.repeatedForeignEnumArray replaceValueAtIndex:1 withValue:ForeignEnum_ForeignFoo]; + [message.repeatedImportEnumArray replaceValueAtIndex:1 withValue:ImportEnum_ImportFoo]; + + [message.repeatedStringPieceArray replaceObjectAtIndex:1 withObject:@"524"]; + [message.repeatedCordArray replaceObjectAtIndex:1 withObject:@"525"]; +} + +- (void)assertRepeatedFieldsModified:(TestAllTypes *)message + repeatedCount:(uint32_t)count { + // ModifyRepeatedFields only sets the second repeated element of each + // field. In addition to verifying this, we also verify that the first + // element and size were *not* modified. + XCTAssertEqual(count, message.repeatedInt32Array.count); + XCTAssertEqual(count, message.repeatedInt64Array.count); + XCTAssertEqual(count, message.repeatedUint32Array.count); + XCTAssertEqual(count, message.repeatedUint64Array.count); + XCTAssertEqual(count, message.repeatedSint32Array.count); + XCTAssertEqual(count, message.repeatedSint64Array.count); + XCTAssertEqual(count, message.repeatedFixed32Array.count); + XCTAssertEqual(count, message.repeatedFixed64Array.count); + XCTAssertEqual(count, message.repeatedSfixed32Array.count); + XCTAssertEqual(count, message.repeatedSfixed64Array.count); + XCTAssertEqual(count, message.repeatedFloatArray.count); + XCTAssertEqual(count, message.repeatedDoubleArray.count); + XCTAssertEqual(count, message.repeatedBoolArray.count); + XCTAssertEqual(count, message.repeatedStringArray.count); + XCTAssertEqual(count, message.repeatedBytesArray.count); + + XCTAssertEqual(count, message.repeatedGroupArray.count); + XCTAssertEqual(count, message.repeatedNestedMessageArray.count); + XCTAssertEqual(count, message.repeatedForeignMessageArray.count); + XCTAssertEqual(count, message.repeatedImportMessageArray.count); + XCTAssertEqual(count, message.repeatedNestedEnumArray.count); + XCTAssertEqual(count, message.repeatedForeignEnumArray.count); + XCTAssertEqual(count, message.repeatedImportEnumArray.count); + + XCTAssertEqual(count, message.repeatedStringPieceArray.count); + XCTAssertEqual(count, message.repeatedCordArray.count); + + XCTAssertEqual(201, [message.repeatedInt32Array valueAtIndex:0]); + XCTAssertEqual(202LL, [message.repeatedInt64Array valueAtIndex:0]); + XCTAssertEqual(203U, [message.repeatedUint32Array valueAtIndex:0]); + XCTAssertEqual(204ULL, [message.repeatedUint64Array valueAtIndex:0]); + XCTAssertEqual(205, [message.repeatedSint32Array valueAtIndex:0]); + XCTAssertEqual(206LL, [message.repeatedSint64Array valueAtIndex:0]); + XCTAssertEqual(207U, [message.repeatedFixed32Array valueAtIndex:0]); + XCTAssertEqual(208ULL, [message.repeatedFixed64Array valueAtIndex:0]); + XCTAssertEqual(209, [message.repeatedSfixed32Array valueAtIndex:0]); + XCTAssertEqual(210LL, [message.repeatedSfixed64Array valueAtIndex:0]); + XCTAssertEqualWithAccuracy(211.0f, [message.repeatedFloatArray valueAtIndex:0], 0.01); + XCTAssertEqualWithAccuracy(212.0, [message.repeatedDoubleArray valueAtIndex:0], 0.01); + XCTAssertFalse([message.repeatedBoolArray valueAtIndex:0]); + XCTAssertEqualObjects(@"215", message.repeatedStringArray[0]); + XCTAssertEqualObjects([NSData gpbtu_dataWithUint32:216], + message.repeatedBytesArray[0]); + + XCTAssertEqual(217, ((TestAllTypes_RepeatedGroup*)message.repeatedGroupArray[0]).a); + XCTAssertEqual(218, ((TestAllTypes_NestedMessage*)message.repeatedNestedMessageArray[0]).bb); + XCTAssertEqual(219, ((ForeignMessage*)message.repeatedForeignMessageArray[0]).c); + XCTAssertEqual(220, ((ImportMessage*)message.repeatedImportMessageArray[0]).d); + + XCTAssertEqual(TestAllTypes_NestedEnum_Baz, [message.repeatedNestedEnumArray valueAtIndex:0]); + XCTAssertEqual(ForeignEnum_ForeignBaz, [message.repeatedForeignEnumArray valueAtIndex:0]); + XCTAssertEqual(ImportEnum_ImportBaz, [message.repeatedImportEnumArray valueAtIndex:0]); + + XCTAssertEqualObjects(@"224", message.repeatedStringPieceArray[0]); + XCTAssertEqualObjects(@"225", message.repeatedCordArray[0]); + + // Actually verify the second (modified) elements now. + XCTAssertEqual(501, [message.repeatedInt32Array valueAtIndex:1]); + XCTAssertEqual(502LL, [message.repeatedInt64Array valueAtIndex:1]); + XCTAssertEqual(503U, [message.repeatedUint32Array valueAtIndex:1]); + XCTAssertEqual(504ULL, [message.repeatedUint64Array valueAtIndex:1]); + XCTAssertEqual(505, [message.repeatedSint32Array valueAtIndex:1]); + XCTAssertEqual(506LL, [message.repeatedSint64Array valueAtIndex:1]); + XCTAssertEqual(507U, [message.repeatedFixed32Array valueAtIndex:1]); + XCTAssertEqual(508ULL, [message.repeatedFixed64Array valueAtIndex:1]); + XCTAssertEqual(509, [message.repeatedSfixed32Array valueAtIndex:1]); + XCTAssertEqual(510LL, [message.repeatedSfixed64Array valueAtIndex:1]); + XCTAssertEqualWithAccuracy(511.0f, [message.repeatedFloatArray valueAtIndex:1], 0.01); + XCTAssertEqualWithAccuracy(512.0, [message.repeatedDoubleArray valueAtIndex:1], 0.01); + XCTAssertTrue([message.repeatedBoolArray valueAtIndex:1]); + XCTAssertEqualObjects(@"515", message.repeatedStringArray[1]); + XCTAssertEqualObjects([NSData gpbtu_dataWithUint32:516], + message.repeatedBytesArray[1]); + + XCTAssertEqual(517, ((TestAllTypes_RepeatedGroup*)message.repeatedGroupArray[1]).a); + XCTAssertEqual(518, ((TestAllTypes_NestedMessage*)message.repeatedNestedMessageArray[1]).bb); + XCTAssertEqual(519, ((ForeignMessage*)message.repeatedForeignMessageArray[1]).c); + XCTAssertEqual(520, ((ImportMessage*)message.repeatedImportMessageArray[1]).d); + + XCTAssertEqual(TestAllTypes_NestedEnum_Foo, [message.repeatedNestedEnumArray valueAtIndex:1]); + XCTAssertEqual(ForeignEnum_ForeignFoo, [message.repeatedForeignEnumArray valueAtIndex:1]); + XCTAssertEqual(ImportEnum_ImportFoo, [message.repeatedImportEnumArray valueAtIndex:1]); + + XCTAssertEqualObjects(@"524", message.repeatedStringPieceArray[1]); + XCTAssertEqualObjects(@"525", message.repeatedCordArray[1]); +} + +- (void)setPackedFields:(TestPackedTypes *)message + repeatedCount:(uint32_t)count { + { + GPBInt32Array *scratch = [GPBInt32Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:601 + i * 100]; + } + [message setPackedInt32Array:scratch]; + } + { + GPBInt64Array *scratch = [GPBInt64Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:602 + i * 100]; + } + [message setPackedInt64Array:scratch]; + } + { + GPBUInt32Array *scratch = [GPBUInt32Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:603 + i * 100]; + } + [message setPackedUint32Array:scratch]; + } + { + GPBUInt64Array *scratch = [GPBUInt64Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:604 + i * 100]; + } + [message setPackedUint64Array:scratch]; + } + { + GPBInt32Array *scratch = [GPBInt32Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:605 + i * 100]; + } + [message setPackedSint32Array:scratch]; + } + { + GPBInt64Array *scratch = [GPBInt64Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:606 + i * 100]; + } + [message setPackedSint64Array:scratch]; + } + { + GPBUInt32Array *scratch = [GPBUInt32Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:607 + i * 100]; + } + [message setPackedFixed32Array:scratch]; + } + { + GPBUInt64Array *scratch = [GPBUInt64Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:608 + i * 100]; + } + [message setPackedFixed64Array:scratch]; + } + { + GPBInt32Array *scratch = [GPBInt32Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:609 + i * 100]; + } + [message setPackedSfixed32Array:scratch]; + } + { + GPBInt64Array *scratch = [GPBInt64Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:610 + i * 100]; + } + [message setPackedSfixed64Array:scratch]; + } + { + GPBFloatArray *scratch = [GPBFloatArray array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:611 + i * 100]; + } + [message setPackedFloatArray:scratch]; + } + { + GPBDoubleArray *scratch = [GPBDoubleArray array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:612 + i * 100]; + } + [message setPackedDoubleArray:scratch]; + } + { + GPBBoolArray *scratch = [GPBBoolArray array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:(i % 2) ? YES : NO]; + } + [message setPackedBoolArray:scratch]; + } + { + GPBEnumArray *scratch = + [GPBEnumArray arrayWithValidationFunction:ForeignEnum_IsValidValue]; + for (uint32_t i = 0; i < count; ++i) { + [scratch + addValue:(i % 2) ? ForeignEnum_ForeignBar : ForeignEnum_ForeignBaz]; + } + [message setPackedEnumArray:scratch]; + } +} + +- (void)assertPackedFieldsSet:(TestPackedTypes *)message + repeatedCount:(uint32_t)count { + XCTAssertEqual(count, message.packedInt32Array.count); + XCTAssertEqual(count, message.packedInt64Array.count); + XCTAssertEqual(count, message.packedUint32Array.count); + XCTAssertEqual(count, message.packedUint64Array.count); + XCTAssertEqual(count, message.packedSint32Array.count); + XCTAssertEqual(count, message.packedSint64Array.count); + XCTAssertEqual(count, message.packedFixed32Array.count); + XCTAssertEqual(count, message.packedFixed64Array.count); + XCTAssertEqual(count, message.packedSfixed32Array.count); + XCTAssertEqual(count, message.packedSfixed64Array.count); + XCTAssertEqual(count, message.packedFloatArray.count); + XCTAssertEqual(count, message.packedDoubleArray.count); + XCTAssertEqual(count, message.packedBoolArray.count); + XCTAssertEqual(count, message.packedEnumArray.count); + for (uint32_t i = 0; i < count; ++i) { + XCTAssertEqual((int)(601 + i * 100), + [message.packedInt32Array valueAtIndex:i]); + XCTAssertEqual(602 + i * 100, [message.packedInt64Array valueAtIndex:i]); + XCTAssertEqual(603 + i * 100, [message.packedUint32Array valueAtIndex:i]); + XCTAssertEqual(604 + i * 100, [message.packedUint64Array valueAtIndex:i]); + XCTAssertEqual((int)(605 + i * 100), + [message.packedSint32Array valueAtIndex:i]); + XCTAssertEqual(606 + i * 100, [message.packedSint64Array valueAtIndex:i]); + XCTAssertEqual(607 + i * 100, [message.packedFixed32Array valueAtIndex:i]); + XCTAssertEqual(608 + i * 100, [message.packedFixed64Array valueAtIndex:i]); + XCTAssertEqual((int)(609 + i * 100), + [message.packedSfixed32Array valueAtIndex:i]); + XCTAssertEqual(610 + i * 100, [message.packedSfixed64Array valueAtIndex:i]); + XCTAssertEqualWithAccuracy(611 + i * 100, + [message.packedFloatArray valueAtIndex:i], 0.01); + XCTAssertEqualWithAccuracy( + 612 + i * 100, [message.packedDoubleArray valueAtIndex:i], 0.01); + XCTAssertEqual((i % 2) ? YES : NO, + [message.packedBoolArray valueAtIndex:i]); + XCTAssertEqual((i % 2) ? ForeignEnum_ForeignBar : ForeignEnum_ForeignBaz, + [message.packedEnumArray valueAtIndex:i]); + } +} + +- (void)setPackedExtensions:(TestPackedExtensions *)message + repeatedCount:(uint32_t)count { + for (uint32_t i = 0; i < count; i++) { + [message addExtension:[UnittestRoot packedInt32Extension] + value:@(601 + i * 100)]; + [message addExtension:[UnittestRoot packedInt64Extension] + value:@(602 + i * 100)]; + [message addExtension:[UnittestRoot packedUint32Extension] + value:@(603 + i * 100)]; + [message addExtension:[UnittestRoot packedUint64Extension] + value:@(604 + i * 100)]; + [message addExtension:[UnittestRoot packedSint32Extension] + value:@(605 + i * 100)]; + [message addExtension:[UnittestRoot packedSint64Extension] + value:@(606 + i * 100)]; + [message addExtension:[UnittestRoot packedFixed32Extension] + value:@(607 + i * 100)]; + [message addExtension:[UnittestRoot packedFixed64Extension] + value:@(608 + i * 100)]; + [message addExtension:[UnittestRoot packedSfixed32Extension] + value:@(609 + i * 100)]; + [message addExtension:[UnittestRoot packedSfixed64Extension] + value:@(610 + i * 100)]; + [message addExtension:[UnittestRoot packedFloatExtension] + value:@(611 + i * 100)]; + [message addExtension:[UnittestRoot packedDoubleExtension] + value:@(612 + i * 100)]; + [message addExtension:[UnittestRoot packedBoolExtension] + value:@((i % 2) ? YES : NO)]; + [message addExtension:[UnittestRoot packedEnumExtension] + value:@((i % 2) ? ForeignEnum_ForeignBar + : ForeignEnum_ForeignBaz)]; + } +} + +- (void)assertPackedExtensionsSet:(TestPackedExtensions *)message + repeatedCount:(uint32_t)count{ + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedInt32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedInt64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedUint32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedUint64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedSint32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedSint64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedFixed32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedFixed64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedSfixed32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedSfixed64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedFloatExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedDoubleExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedBoolExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedEnumExtension]] count]); + + for (uint32_t i = 0; i < count; ++i) { + id extension = [message getExtension:[UnittestRoot packedInt32Extension]]; + XCTAssertEqual((int)(601 + i * 100), [extension[i] intValue]); + extension = [message getExtension:[UnittestRoot packedInt64Extension]]; + XCTAssertEqual(602 + i * 100, [extension[i] longLongValue]); + extension = [message getExtension:[UnittestRoot packedUint32Extension]]; + XCTAssertEqual(603 + i * 100, [extension[i] unsignedIntValue]); + extension = [message getExtension:[UnittestRoot packedUint64Extension]]; + XCTAssertEqual(604 + i * 100, [extension[i] unsignedLongLongValue]); + extension = [message getExtension:[UnittestRoot packedSint32Extension]]; + XCTAssertEqual((int)(605 + i * 100), [extension[i] intValue]); + extension = [message getExtension:[UnittestRoot packedSint64Extension]]; + XCTAssertEqual(606 + i * 100, [extension[i] longLongValue]); + extension = [message getExtension:[UnittestRoot packedFixed32Extension]]; + XCTAssertEqual(607 + i * 100, [extension[i] unsignedIntValue]); + extension = [message getExtension:[UnittestRoot packedFixed64Extension]]; + XCTAssertEqual(608 + i * 100, [extension[i] unsignedLongLongValue]); + extension = [message getExtension:[UnittestRoot packedSfixed32Extension]]; + XCTAssertEqual((int)(609 + i * 100), [extension[i] intValue]); + extension = [message getExtension:[UnittestRoot packedSfixed64Extension]]; + XCTAssertEqual(610 + i * 100, [extension[i] longLongValue]); + extension = [message getExtension:[UnittestRoot packedFloatExtension]]; + XCTAssertEqualWithAccuracy(611 + i * 100, [extension[i] floatValue], 0.01); + extension = [message getExtension:[UnittestRoot packedDoubleExtension]]; + XCTAssertEqualWithAccuracy(612 + i * 100, [extension[i] doubleValue], 0.01); + extension = [message getExtension:[UnittestRoot packedBoolExtension]]; + XCTAssertEqual((i % 2) ? YES : NO, [extension[i] boolValue]); + extension = [message getExtension:[UnittestRoot packedEnumExtension]]; + XCTAssertEqual((i % 2) ? ForeignEnum_ForeignBar : ForeignEnum_ForeignBaz, + [extension[i] intValue]); + } +} + +- (void)assertAllFieldsKVCMatch:(TestAllTypes *)message { + XCTAssertEqualObjects([message valueForKey:@"hasOptionalInt32"], @YES); + XCTAssertEqualObjects(@(message.optionalInt32), [message valueForKey:@"optionalInt32"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalInt64"], @YES); + XCTAssertEqualObjects(@(message.optionalInt64), [message valueForKey:@"optionalInt64"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalUint32"], @YES); + XCTAssertEqualObjects(@(message.optionalUint32), [message valueForKey:@"optionalUint32"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalUint64"], @YES); + XCTAssertEqualObjects(@(message.optionalUint64), [message valueForKey:@"optionalUint64"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalSint32"], @YES); + XCTAssertEqualObjects(@(message.optionalSint32), [message valueForKey:@"optionalSint32"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalSint64"], @YES); + XCTAssertEqualObjects(@(message.optionalSint64), [message valueForKey:@"optionalSint64"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalFixed32"], @YES); + XCTAssertEqualObjects(@(message.optionalFixed32), [message valueForKey:@"optionalFixed32"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalFixed64"], @YES); + XCTAssertEqualObjects(@(message.optionalFixed64), [message valueForKey:@"optionalFixed64"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalSfixed32"], @YES); + XCTAssertEqualObjects(@(message.optionalSfixed32), [message valueForKey:@"optionalSfixed32"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalSfixed64"], @YES); + XCTAssertEqualObjects(@(message.optionalSfixed64), [message valueForKey:@"optionalSfixed64"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalFloat"], @YES); + XCTAssertEqualObjects(@(message.optionalFloat), [message valueForKey:@"optionalFloat"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalDouble"], @YES); + XCTAssertEqualObjects(@(message.optionalDouble), [message valueForKey:@"optionalDouble"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalBool"], @YES); + XCTAssertEqualObjects(@(message.optionalBool), [message valueForKey:@"optionalBool"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalString"], @YES); + XCTAssertEqualObjects(message.optionalString, [message valueForKey:@"optionalString"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalBytes"], @YES); + XCTAssertEqualObjects(message.optionalBytes, [message valueForKey:@"optionalBytes"]); + + XCTAssertEqualObjects([message valueForKey:@"hasOptionalGroup"], @YES); + XCTAssertNotNil(message.optionalGroup); + XCTAssertEqualObjects([message valueForKeyPath:@"optionalGroup.hasA"], @YES); + XCTAssertEqualObjects(@(message.optionalGroup.a), [message valueForKeyPath:@"optionalGroup.a"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalNestedMessage"], @YES); + XCTAssertNotNil(message.optionalNestedMessage); + XCTAssertEqualObjects([message valueForKeyPath:@"optionalNestedMessage.hasBb"], @YES); + XCTAssertEqualObjects(@(message.optionalNestedMessage.bb), [message valueForKeyPath:@"optionalNestedMessage.bb"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalForeignMessage"], @YES); + XCTAssertNotNil(message.optionalForeignMessage); + XCTAssertEqualObjects([message valueForKeyPath:@"optionalForeignMessage.hasC"], @YES); + XCTAssertEqualObjects(@(message.optionalForeignMessage.c), [message valueForKeyPath:@"optionalForeignMessage.c"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalImportMessage"], @YES); + XCTAssertNotNil(message.optionalForeignMessage); + XCTAssertEqualObjects([message valueForKeyPath:@"optionalImportMessage.hasD"], @YES); + XCTAssertEqualObjects(@(message.optionalImportMessage.d), [message valueForKeyPath:@"optionalImportMessage.d"]); + + XCTAssertEqualObjects([message valueForKey:@"hasOptionalNestedEnum"], @YES); + XCTAssertEqualObjects(@(message.optionalNestedEnum), [message valueForKey:@"optionalNestedEnum"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalForeignEnum"], @YES); + XCTAssertEqualObjects(@(message.optionalForeignEnum), [message valueForKey:@"optionalForeignEnum"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalImportEnum"], @YES); + XCTAssertEqualObjects(@(message.optionalImportEnum), [message valueForKey:@"optionalImportEnum"]); + + XCTAssertEqualObjects([message valueForKey:@"hasOptionalStringPiece"], @YES); + XCTAssertEqualObjects(message.optionalStringPiece, [message valueForKey:@"optionalStringPiece"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalCord"], @YES); + XCTAssertEqualObjects(message.optionalCord, [message valueForKey:@"optionalCord"]); + + // ----------------------------------------------------------------- + + // GPBArray interface for repeated + + XCTAssertEqualObjects(message.repeatedInt32Array, [message valueForKey:@"repeatedInt32Array"]); + XCTAssertEqualObjects(message.repeatedInt64Array, [message valueForKey:@"repeatedInt64Array"]); + XCTAssertEqualObjects(message.repeatedUint32Array, [message valueForKey:@"repeatedUint32Array"]); + XCTAssertEqualObjects(message.repeatedUint64Array, [message valueForKey:@"repeatedUint64Array"]); + XCTAssertEqualObjects(message.repeatedSint32Array, [message valueForKey:@"repeatedSint32Array"]); + XCTAssertEqualObjects(message.repeatedSint64Array, [message valueForKey:@"repeatedSint64Array"]); + XCTAssertEqualObjects(message.repeatedFixed32Array, [message valueForKey:@"repeatedFixed32Array"]); + XCTAssertEqualObjects(message.repeatedFixed64Array, [message valueForKey:@"repeatedFixed64Array"]); + XCTAssertEqualObjects(message.repeatedSfixed32Array, [message valueForKey:@"repeatedSfixed32Array"]); + XCTAssertEqualObjects(message.repeatedSfixed64Array, [message valueForKey:@"repeatedSfixed64Array"]); + XCTAssertEqualObjects(message.repeatedFloatArray, [message valueForKey:@"repeatedFloatArray"]); + XCTAssertEqualObjects(message.repeatedDoubleArray, [message valueForKey:@"repeatedDoubleArray"]); + XCTAssertEqualObjects(message.repeatedBoolArray, [message valueForKey:@"repeatedBoolArray"]); + XCTAssertEqualObjects(message.repeatedStringArray, [message valueForKey:@"repeatedStringArray"]); + XCTAssertEqualObjects(message.repeatedBytesArray, [message valueForKey:@"repeatedBytesArray"]); + + XCTAssertEqualObjects(message.repeatedGroupArray, [message valueForKey:@"repeatedGroupArray"]); + XCTAssertEqualObjects(message.repeatedNestedMessageArray, [message valueForKey:@"repeatedNestedMessageArray"]); + XCTAssertEqualObjects(message.repeatedForeignMessageArray, [message valueForKey:@"repeatedForeignMessageArray"]); + XCTAssertEqualObjects(message.repeatedImportMessageArray, [message valueForKey:@"repeatedImportMessageArray"]); + + XCTAssertEqualObjects(message.repeatedNestedEnumArray, [message valueForKey:@"repeatedNestedEnumArray"]); + XCTAssertEqualObjects(message.repeatedForeignEnumArray, [message valueForKey:@"repeatedForeignEnumArray"]); + XCTAssertEqualObjects(message.repeatedImportEnumArray, [message valueForKey:@"repeatedImportEnumArray"]); + + XCTAssertEqualObjects(message.repeatedStringPieceArray, [message valueForKey:@"repeatedStringPieceArray"]); + XCTAssertEqualObjects(message.repeatedCordArray, [message valueForKey:@"repeatedCordArray"]); + + // ----------------------------------------------------------------- + + XCTAssertEqualObjects([message valueForKey:@"hasDefaultInt32"], @YES); + XCTAssertEqualObjects(@(message.defaultInt32), [message valueForKey:@"defaultInt32"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultInt64"], @YES); + XCTAssertEqualObjects(@(message.defaultInt64), [message valueForKey:@"defaultInt64"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultUint32"], @YES); + XCTAssertEqualObjects(@(message.defaultUint32), [message valueForKey:@"defaultUint32"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultUint64"], @YES); + XCTAssertEqualObjects(@(message.defaultUint64), [message valueForKey:@"defaultUint64"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultSint32"], @YES); + XCTAssertEqualObjects(@(message.defaultSint32), [message valueForKey:@"defaultSint32"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultSint64"], @YES); + XCTAssertEqualObjects(@(message.defaultSint64), [message valueForKey:@"defaultSint64"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultFixed32"], @YES); + XCTAssertEqualObjects(@(message.defaultFixed32), [message valueForKey:@"defaultFixed32"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultFixed64"], @YES); + XCTAssertEqualObjects(@(message.defaultFixed64), [message valueForKey:@"defaultFixed64"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultSfixed32"], @YES); + XCTAssertEqualObjects(@(message.defaultSfixed32), [message valueForKey:@"defaultSfixed32"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultSfixed64"], @YES); + XCTAssertEqualObjects(@(message.defaultSfixed64), [message valueForKey:@"defaultSfixed64"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultFloat"], @YES); + XCTAssertEqualObjects(@(message.defaultFloat), [message valueForKey:@"defaultFloat"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultDouble"], @YES); + XCTAssertEqualObjects(@(message.defaultDouble), [message valueForKey:@"defaultDouble"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultBool"], @YES); + XCTAssertEqualObjects(@(message.defaultBool), [message valueForKey:@"defaultBool"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultString"], @YES); + XCTAssertEqualObjects(message.defaultString, [message valueForKey:@"defaultString"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultBytes"], @YES); + XCTAssertEqualObjects(message.defaultBytes, [message valueForKey:@"defaultBytes"]); + + XCTAssertEqualObjects([message valueForKey:@"hasDefaultNestedEnum"], @YES); + XCTAssertEqualObjects(@(message.defaultNestedEnum), [message valueForKey:@"defaultNestedEnum"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultForeignEnum"], @YES); + XCTAssertEqualObjects(@(message.defaultForeignEnum), [message valueForKey:@"defaultForeignEnum"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultImportEnum"], @YES); + XCTAssertEqualObjects(@(message.defaultImportEnum), [message valueForKey:@"defaultImportEnum"]); + + XCTAssertEqualObjects([message valueForKey:@"hasDefaultStringPiece"], @YES); + XCTAssertEqualObjects(message.defaultStringPiece, [message valueForKey:@"defaultStringPiece"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultCord"], @YES); + XCTAssertEqualObjects(message.defaultCord, [message valueForKey:@"defaultCord"]); +} + +- (void)setAllFieldsViaKVC:(TestAllTypes *)message + repeatedCount:(uint32_t)count { + [message setValue:@101 forKey:@"optionalInt32"]; + [message setValue:@102 forKey:@"optionalInt64"]; + [message setValue:@103 forKey:@"optionalUint32"]; + [message setValue:@104 forKey:@"optionalUint64"]; + [message setValue:@105 forKey:@"optionalSint32"]; + [message setValue:@106 forKey:@"optionalSint64"]; + [message setValue:@107 forKey:@"optionalFixed32"]; + [message setValue:@108 forKey:@"optionalFixed64"]; + [message setValue:@109 forKey:@"optionalSfixed32"]; + [message setValue:@110 forKey:@"optionalSfixed64"]; + [message setValue:@111 forKey:@"optionalFloat"]; + [message setValue:@112 forKey:@"optionalDouble"]; + [message setValue:@YES forKey:@"optionalBool"]; + [message setValue:@"115" forKey:@"optionalString"]; + [message setValue:[NSData gpbtu_dataWithEmbeddedNulls] + forKey:@"optionalBytes"]; + + TestAllTypes_OptionalGroup *allTypes = [TestAllTypes_OptionalGroup message]; + [allTypes setValue:@117 forKey:@"a"]; + [message setValue:allTypes forKey:@"optionalGroup"]; + TestAllTypes_NestedMessage *nestedMessage = + [TestAllTypes_NestedMessage message]; + [nestedMessage setValue:@118 forKey:@"bb"]; + [message setValue:nestedMessage forKey:@"optionalNestedMessage"]; + ForeignMessage *foreignMessage = [ForeignMessage message]; + [foreignMessage setValue:@119 forKey:@"c"]; + [message setValue:foreignMessage forKey:@"optionalForeignMessage"]; + ImportMessage *importMessage = [ImportMessage message]; + [importMessage setValue:@120 forKey:@"d"]; + [message setValue:importMessage forKey:@"optionalImportMessage"]; + + [message setValue:@(TestAllTypes_NestedEnum_Baz) + forKey:@"optionalNestedEnum"]; + [message setValue:@(ForeignEnum_ForeignBaz) forKey:@"optionalForeignEnum"]; + [message setValue:@(ImportEnum_ImportBaz) forKey:@"optionalImportEnum"]; + + [message setValue:@"124" forKey:@"optionalStringPiece"]; + [message setValue:@"125" forKey:@"optionalCord"]; + + // ----------------------------------------------------------------- + + { + GPBInt32Array *scratch = [GPBInt32Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:201 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedInt32Array"]; + } + { + GPBInt64Array *scratch = [GPBInt64Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:202 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedInt64Array"]; + } + { + GPBUInt32Array *scratch = [GPBUInt32Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:203 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedUint32Array"]; + } + { + GPBUInt64Array *scratch = [GPBUInt64Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:204 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedUint64Array"]; + } + { + GPBInt32Array *scratch = [GPBInt32Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:205 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedSint32Array"]; + } + { + GPBInt64Array *scratch = [GPBInt64Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:206 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedSint64Array"]; + } + { + GPBUInt32Array *scratch = [GPBUInt32Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:207 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedFixed32Array"]; + } + { + GPBUInt64Array *scratch = [GPBUInt64Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:208 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedFixed64Array"]; + } + { + GPBInt32Array *scratch = [GPBInt32Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:209 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedSfixed32Array"]; + } + { + GPBInt64Array *scratch = [GPBInt64Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:210 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedSfixed64Array"]; + } + { + GPBFloatArray *scratch = [GPBFloatArray array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:211 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedFloatArray"]; + } + { + GPBDoubleArray *scratch = [GPBDoubleArray array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:212 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedDoubleArray"]; + } + { + GPBBoolArray *scratch = [GPBBoolArray array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:(i % 2) ? YES : NO]; + } + [message setValue:scratch forKey:@"repeatedBoolArray"]; + } + + NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:count]; + for (uint32_t i = 0; i < count; ++i) { + NSString *string = [[NSString alloc] initWithFormat:@"%d", 215 + i * 100]; + [array addObject:string]; + [string release]; + } + [message setValue:array forKey:@"repeatedStringArray"]; + [array release]; + + array = [[NSMutableArray alloc] initWithCapacity:count]; + for (uint32_t i = 0; i < count; ++i) { + NSData *data = [[NSData alloc] initWithUint32_gpbtu:216 + i * 100]; + [array addObject:data]; + [data release]; + } + [message setValue:array forKey:@"repeatedBytesArray"]; + [array release]; + + array = [[NSMutableArray alloc] initWithCapacity:count]; + for (uint32_t i = 0; i < count; ++i) { + TestAllTypes_RepeatedGroup *testAll = + [[TestAllTypes_RepeatedGroup alloc] init]; + [testAll setA:217 + i * 100]; + [array addObject:testAll]; + [testAll release]; + } + [message setValue:array forKey:@"repeatedGroupArray"]; + [array release]; + + array = [[NSMutableArray alloc] initWithCapacity:count]; + for (uint32_t i = 0; i < count; ++i) { + nestedMessage = [[TestAllTypes_NestedMessage alloc] init]; + [nestedMessage setBb:218 + i * 100]; + [array addObject:nestedMessage]; + [nestedMessage release]; + } + [message setValue:array forKey:@"repeatedNestedMessageArray"]; + [array release]; + + array = [[NSMutableArray alloc] initWithCapacity:count]; + for (uint32_t i = 0; i < count; ++i) { + foreignMessage = [[ForeignMessage alloc] init]; + [foreignMessage setC:219 + i * 100]; + [array addObject:foreignMessage]; + [foreignMessage release]; + } + [message setValue:array forKey:@"repeatedForeignMessageArray"]; + [array release]; + + array = [[NSMutableArray alloc] initWithCapacity:count]; + for (uint32_t i = 0; i < count; ++i) { + importMessage = [[ImportMessage alloc] init]; + [importMessage setD:220 + i * 100]; + [array addObject:importMessage]; + [importMessage release]; + } + [message setValue:array forKey:@"repeatedImportMessageArray"]; + [array release]; + + { + GPBEnumArray *scratch = [GPBEnumArray + arrayWithValidationFunction:TestAllTypes_NestedEnum_IsValidValue]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:(i % 2) ? TestAllTypes_NestedEnum_Bar + : TestAllTypes_NestedEnum_Baz]; + } + [message setValue:scratch forKey:@"repeatedNestedEnumArray"]; + } + { + GPBEnumArray *scratch = + [GPBEnumArray arrayWithValidationFunction:ForeignEnum_IsValidValue]; + for (uint32_t i = 0; i < count; ++i) { + [scratch + addValue:(i % 2) ? ForeignEnum_ForeignBar : ForeignEnum_ForeignBaz]; + } + [message setValue:scratch forKey:@"repeatedForeignEnumArray"]; + } + { + GPBEnumArray *scratch = + [GPBEnumArray arrayWithValidationFunction:ImportEnum_IsValidValue]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:(i % 2) ? ImportEnum_ImportBar : ImportEnum_ImportBaz]; + } + [message setValue:scratch forKey:@"repeatedImportEnumArray"]; + } + + array = [[NSMutableArray alloc] initWithCapacity:count]; + for (uint32_t i = 0; i < count; ++i) { + NSString *string = [[NSString alloc] initWithFormat:@"%d", 224 + i * 100]; + [array addObject:string]; + [string release]; + } + [message setValue:array forKey:@"repeatedStringPieceArray"]; + [array release]; + + array = [[NSMutableArray alloc] initWithCapacity:count]; + for (uint32_t i = 0; i < count; ++i) { + NSString *string = [[NSString alloc] initWithFormat:@"%d", 225 + i * 100]; + [array addObject:string]; + [string release]; + } + [message setValue:array forKey:@"repeatedCordArray"]; + [array release]; + + // ----------------------------------------------------------------- + + [message setValue:@401 forKey:@"defaultInt32"]; + [message setValue:@402 forKey:@"defaultInt64"]; + [message setValue:@403 forKey:@"defaultUint32"]; + [message setValue:@404 forKey:@"defaultUint64"]; + [message setValue:@405 forKey:@"defaultSint32"]; + [message setValue:@406 forKey:@"defaultSint64"]; + [message setValue:@407 forKey:@"defaultFixed32"]; + [message setValue:@408 forKey:@"defaultFixed64"]; + [message setValue:@409 forKey:@"defaultSfixed32"]; + [message setValue:@410 forKey:@"defaultSfixed64"]; + [message setValue:@411 forKey:@"defaultFloat"]; + [message setValue:@412 forKey:@"defaultDouble"]; + [message setValue:@NO forKey:@"defaultBool"]; + [message setValue:@"415" forKey:@"defaultString"]; + [message setValue:[NSData gpbtu_dataWithUint32:416] forKey:@"defaultBytes"]; + + [message setValue:@(TestAllTypes_NestedEnum_Foo) forKey:@"defaultNestedEnum"]; + [message setValue:@(ForeignEnum_ForeignFoo) forKey:@"defaultForeignEnum"]; + [message setValue:@(ImportEnum_ImportFoo) forKey:@"defaultImportEnum"]; + + [message setValue:@"424" forKey:@"defaultStringPiece"]; + [message setValue:@"425" forKey:@"defaultCord"]; +} + +- (void)assertClearKVC:(TestAllTypes *)message { + XCTAssertEqualObjects([message valueForKey:@"hasOptionalInt32"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalInt64"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalUint32"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalUint64"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalSint32"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalSint64"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalFixed32"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalFixed64"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalSfixed32"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalSfixed64"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalFloat"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalDouble"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalBool"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalString"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalBytes"], @NO); + + XCTAssertEqualObjects([message valueForKey:@"hasOptionalGroup"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalNestedMessage"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalForeignMessage"], + @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalImportMessage"], @NO); + + XCTAssertEqualObjects([message valueForKey:@"hasOptionalNestedEnum"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalForeignEnum"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalImportEnum"], @NO); + + XCTAssertEqualObjects([message valueForKey:@"hasOptionalStringPiece"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalCord"], @NO); + + // Optional fields without defaults are set to zero or something like it. + XCTAssertEqualObjects([message valueForKey:@"optionalInt32"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalInt64"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalUint32"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalUint64"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalSint32"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalSint64"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalFixed32"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalFixed64"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalSfixed32"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalSfixed64"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalFloat"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalDouble"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalBool"], @NO); + XCTAssertEqualObjects([message valueForKey:@"optionalString"], @""); + XCTAssertEqualObjects([message valueForKey:@"optionalBytes"], + GPBEmptyNSData()); + + // Embedded messages should also be exist, but be clear. + XCTAssertNotNil([message valueForKeyPath:@"optionalGroup"]); + XCTAssertNotNil([message valueForKeyPath:@"optionalNestedMessage"]); + XCTAssertNotNil([message valueForKeyPath:@"optionalForeignMessage"]); + XCTAssertNotNil([message valueForKeyPath:@"optionalImportMessage"]); + XCTAssertEqualObjects([message valueForKeyPath:@"optionalGroup.hasA"], @NO); + XCTAssertEqualObjects( + [message valueForKeyPath:@"optionalNestedMessage.hasBb"], @NO); + XCTAssertEqualObjects( + [message valueForKeyPath:@"optionalForeignMessage.hasC"], @NO); + XCTAssertEqualObjects([message valueForKeyPath:@"optionalImportMessage.hasD"], + @NO); + + XCTAssertEqualObjects([message valueForKeyPath:@"optionalGroup.a"], @0); + XCTAssertEqualObjects([message valueForKeyPath:@"optionalNestedMessage.bb"], + @0); + XCTAssertEqualObjects([message valueForKeyPath:@"optionalForeignMessage.c"], + @0); + XCTAssertEqualObjects([message valueForKeyPath:@"optionalImportMessage.d"], + @0); + + // Enums without defaults are set to the first value in the enum. + XCTAssertEqualObjects([message valueForKey:@"optionalNestedEnum"], + @(TestAllTypes_NestedEnum_Foo)); + XCTAssertEqualObjects([message valueForKey:@"optionalForeignEnum"], + @(ForeignEnum_ForeignFoo)); + XCTAssertEqualObjects([message valueForKey:@"optionalImportEnum"], + @(ImportEnum_ImportFoo)); + + XCTAssertEqualObjects([message valueForKey:@"optionalStringPiece"], @""); + XCTAssertEqualObjects([message valueForKey:@"optionalCord"], @""); + + // NSArray interface for repeated doesn't have has*, nil means no value. + + XCTAssertEqualObjects([message valueForKey:@"hasDefaultInt32"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultInt64"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultUint32"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultUint64"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultSint32"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultSint64"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultFixed32"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultFixed64"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultSfixed32"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultSfixed64"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultFloat"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultDouble"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultBool"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultString"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultBytes"], @NO); + + XCTAssertEqualObjects([message valueForKey:@"hasDefaultNestedEnum"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultForeignEnum"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultImportEnum"], @NO); + + XCTAssertEqualObjects([message valueForKey:@"hasDefaultStringPiece"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultCord"], @NO); + + // Fields with defaults have their default values (duh). + XCTAssertEqualObjects([message valueForKey:@"defaultInt32"], @41); + XCTAssertEqualObjects([message valueForKey:@"defaultInt64"], @42); + XCTAssertEqualObjects([message valueForKey:@"defaultUint32"], @43); + XCTAssertEqualObjects([message valueForKey:@"defaultUint64"], @44); + XCTAssertEqualObjects([message valueForKey:@"defaultSint32"], @-45); + XCTAssertEqualObjects([message valueForKey:@"defaultSint64"], @46); + XCTAssertEqualObjects([message valueForKey:@"defaultFixed32"], @47); + XCTAssertEqualObjects([message valueForKey:@"defaultFixed64"], @48); + XCTAssertEqualObjects([message valueForKey:@"defaultSfixed32"], @49); + XCTAssertEqualObjects([message valueForKey:@"defaultSfixed64"], @-50); + XCTAssertEqualObjects([message valueForKey:@"defaultFloat"], @51.5); + XCTAssertEqualObjects([message valueForKey:@"defaultDouble"], @52e3); + XCTAssertEqualObjects([message valueForKey:@"defaultBool"], @YES); + XCTAssertEqualObjects([message valueForKey:@"defaultString"], @"hello"); + XCTAssertEqualObjects([message valueForKey:@"defaultBytes"], + [NSData gpbtu_dataWithCString:"world"]); + + XCTAssertEqualObjects([message valueForKey:@"defaultNestedEnum"], + @(TestAllTypes_NestedEnum_Bar)); + XCTAssertEqualObjects([message valueForKey:@"defaultForeignEnum"], + @(ForeignEnum_ForeignBar)); + XCTAssertEqualObjects([message valueForKey:@"defaultImportEnum"], + @(ImportEnum_ImportBar)); + + XCTAssertEqualObjects([message valueForKey:@"defaultStringPiece"], @"abc"); + XCTAssertEqualObjects([message valueForKey:@"defaultCord"], @"123"); +} + +@end diff --git a/objectivec/Tests/GPBUnittestProtos.m b/objectivec/Tests/GPBUnittestProtos.m new file mode 100644 index 00000000..2c271bf7 --- /dev/null +++ b/objectivec/Tests/GPBUnittestProtos.m @@ -0,0 +1,56 @@ +// 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. + +// Collects all the compiled protos into one file and compiles them to make sure +// the compiler is generating valid code. + +#import "google/protobuf/MapProto2Unittest.pbobjc.m" +#import "google/protobuf/MapUnittest.pbobjc.m" +#import "google/protobuf/Unittest.pbobjc.m" +#import "google/protobuf/UnittestCustomOptions.pbobjc.m" +#import "google/protobuf/UnittestCycle.pbobjc.m" +#import "google/protobuf/UnittestDropUnknownFields.pbobjc.m" +#import "google/protobuf/UnittestEmbedOptimizeFor.pbobjc.m" +#import "google/protobuf/UnittestEmpty.pbobjc.m" +#import "google/protobuf/UnittestEnormousDescriptor.pbobjc.m" +#import "google/protobuf/UnittestFilter.pbobjc.m" +#import "google/protobuf/UnittestImport.pbobjc.m" +#import "google/protobuf/UnittestImportLite.pbobjc.m" +#import "google/protobuf/UnittestImportPublic.pbobjc.m" +#import "google/protobuf/UnittestImportPublicLite.pbobjc.m" +#import "google/protobuf/UnittestLite.pbobjc.m" +#import "google/protobuf/UnittestMset.pbobjc.m" +#import "google/protobuf/UnittestNameMangling.pbobjc.m" +#import "google/protobuf/UnittestNoGenericServices.pbobjc.m" +#import "google/protobuf/UnittestObjc.pbobjc.m" +#import "google/protobuf/UnittestOptimizeFor.pbobjc.m" +#import "google/protobuf/UnittestPreserveUnknownEnum.pbobjc.m" +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.m" +#import "google/protobuf/UnittestRuntimeProto3.pbobjc.m" diff --git a/objectivec/Tests/GPBUnknownFieldSetTest.m b/objectivec/Tests/GPBUnknownFieldSetTest.m new file mode 100644 index 00000000..80186088 --- /dev/null +++ b/objectivec/Tests/GPBUnknownFieldSetTest.m @@ -0,0 +1,255 @@ +// 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. + +#import "GPBTestUtilities.h" + +#import "GPBField_PackagePrivate.h" +#import "GPBUnknownFieldSet_PackagePrivate.h" +#import "google/protobuf/Unittest.pbobjc.h" + +@interface GPBUnknownFieldSet (GPBUnknownFieldSetTest) +- (void)getTags:(int32_t*)tags; +@end + +@interface UnknownFieldSetTest : GPBTestCase { + @private + TestAllTypes* allFields_; + NSData* allFieldsData_; + + // An empty message that has been parsed from allFieldsData. So, it has + // unknown fields of every type. + TestEmptyMessage* emptyMessage_; + GPBUnknownFieldSet* unknownFields_; +} + +@end + +@implementation UnknownFieldSetTest + +- (void)setUp { + allFields_ = [self allSetRepeatedCount:kGPBDefaultRepeatCount]; + allFieldsData_ = [allFields_ data]; + emptyMessage_ = [TestEmptyMessage parseFromData:allFieldsData_]; + unknownFields_ = emptyMessage_.unknownFields; +} + +- (GPBField*)getField:(int32_t)number { + return [unknownFields_ getField:number]; +} + +// Constructs a protocol buffer which contains fields with all the same +// numbers as allFieldsData except that each field is some other wire +// type. +- (NSData*)getBizarroData { + GPBUnknownFieldSet* bizarroFields = + [[[GPBUnknownFieldSet alloc] init] autorelease]; + NSUInteger count = [unknownFields_ countOfFields]; + int32_t tags[count]; + [unknownFields_ getTags:tags]; + for (NSUInteger i = 0; i < count; ++i) { + int32_t tag = tags[i]; + GPBField* field = [unknownFields_ getField:tag]; + if (field.varintList.count == 0) { + // Original field is not a varint, so use a varint. + GPBField* varintField = + [[[GPBField alloc] initWithNumber:tag] autorelease]; + [varintField addVarint:1]; + [bizarroFields addField:varintField]; + } else { + // Original field *is* a varint, so use something else. + GPBField* fixed32Field = + [[[GPBField alloc] initWithNumber:tag] autorelease]; + [fixed32Field addFixed32:1]; + [bizarroFields addField:fixed32Field]; + } + } + + return [bizarroFields data]; +} + +- (void)testSerialize { + // Check that serializing the UnknownFieldSet produces the original data + // again. + NSData* data = [emptyMessage_ data]; + XCTAssertEqualObjects(allFieldsData_, data); +} + +- (void)testCopyFrom { + TestEmptyMessage* message = [TestEmptyMessage message]; + [message mergeFrom:emptyMessage_]; + + XCTAssertEqualObjects(emptyMessage_.data, message.data); +} + +- (void)testMergeFrom { + GPBUnknownFieldSet* set1 = [[[GPBUnknownFieldSet alloc] init] autorelease]; + GPBField* field = [[[GPBField alloc] initWithNumber:2] autorelease]; + [field addVarint:2]; + [set1 addField:field]; + field = [[[GPBField alloc] initWithNumber:3] autorelease]; + [field addVarint:4]; + [set1 addField:field]; + + GPBUnknownFieldSet* set2 = [[[GPBUnknownFieldSet alloc] init] autorelease]; + field = [[[GPBField alloc] initWithNumber:1] autorelease]; + [field addVarint:1]; + [set2 addField:field]; + field = [[[GPBField alloc] initWithNumber:3] autorelease]; + [field addVarint:3]; + [set2 addField:field]; + + GPBUnknownFieldSet* set3 = [[[GPBUnknownFieldSet alloc] init] autorelease]; + field = [[[GPBField alloc] initWithNumber:1] autorelease]; + [field addVarint:1]; + [set3 addField:field]; + field = [[[GPBField alloc] initWithNumber:3] autorelease]; + [field addVarint:4]; + [set3 addField:field]; + + GPBUnknownFieldSet* set4 = [[[GPBUnknownFieldSet alloc] init] autorelease]; + field = [[[GPBField alloc] initWithNumber:2] autorelease]; + [field addVarint:2]; + [set4 addField:field]; + field = [[[GPBField alloc] initWithNumber:3] autorelease]; + [field addVarint:3]; + [set4 addField:field]; + + TestEmptyMessage* source1 = [TestEmptyMessage message]; + [source1 setUnknownFields:set1]; + TestEmptyMessage* source2 = [TestEmptyMessage message]; + [source2 setUnknownFields:set2]; + TestEmptyMessage* source3 = [TestEmptyMessage message]; + [source3 setUnknownFields:set3]; + TestEmptyMessage* source4 = [TestEmptyMessage message]; + [source4 setUnknownFields:set4]; + + TestEmptyMessage* destination1 = [TestEmptyMessage message]; + [destination1 mergeFrom:source1]; + [destination1 mergeFrom:source2]; + + TestEmptyMessage* destination2 = [TestEmptyMessage message]; + [destination2 mergeFrom:source3]; + [destination2 mergeFrom:source4]; + + XCTAssertEqualObjects(destination1.data, destination2.data); +} + +- (void)testClearMessage { + TestEmptyMessage* message = [TestEmptyMessage message]; + [message mergeFrom:emptyMessage_]; + [message clear]; + XCTAssertEqual(message.serializedSize, (size_t)0); +} + +- (void)testParseKnownAndUnknown { + // Test mixing known and unknown fields when parsing. + GPBUnknownFieldSet* fields = [[unknownFields_ copy] autorelease]; + GPBField* field = [[[GPBField alloc] initWithNumber:123456] autorelease]; + [field addVarint:654321]; + [fields addField:field]; + + NSData* data = fields.data; + TestAllTypes* destination = [TestAllTypes parseFromData:data]; + + [self assertAllFieldsSet:destination repeatedCount:kGPBDefaultRepeatCount]; + XCTAssertEqual(destination.unknownFields.countOfFields, (NSUInteger)1); + + GPBField* field2 = [destination.unknownFields getField:123456]; + XCTAssertEqual(field2.varintList.count, (NSUInteger)1); + XCTAssertEqual(654321ULL, [field2.varintList valueAtIndex:0]); +} + +- (void)testWrongTypeTreatedAsUnknown { + // Test that fields of the wrong wire type are treated like unknown fields + // when parsing. + + NSData* bizarroData = [self getBizarroData]; + TestAllTypes* allTypesMessage = [TestAllTypes parseFromData:bizarroData]; + TestEmptyMessage* emptyMessage = [TestEmptyMessage parseFromData:bizarroData]; + + // All fields should have been interpreted as unknown, so the debug strings + // should be the same. + XCTAssertEqualObjects(emptyMessage.data, allTypesMessage.data); +} + +- (void)testUnknownExtensions { + // Make sure fields are properly parsed to the UnknownFieldSet even when + // they are declared as extension numbers. + + TestEmptyMessageWithExtensions* message = + [TestEmptyMessageWithExtensions parseFromData:allFieldsData_]; + + XCTAssertEqual(unknownFields_.countOfFields, + message.unknownFields.countOfFields); + XCTAssertEqualObjects(allFieldsData_, message.data); +} + +- (void)testWrongExtensionTypeTreatedAsUnknown { + // Test that fields of the wrong wire type are treated like unknown fields + // when parsing extensions. + + NSData* bizarroData = [self getBizarroData]; + TestAllExtensions* allExtensionsMessage = + [TestAllExtensions parseFromData:bizarroData]; + TestEmptyMessage* emptyMessage = [TestEmptyMessage parseFromData:bizarroData]; + + // All fields should have been interpreted as unknown, so the debug strings + // should be the same. + XCTAssertEqualObjects(emptyMessage.data, allExtensionsMessage.data); +} + +- (void)testLargeVarint { + GPBUnknownFieldSet* fields = [[unknownFields_ copy] autorelease]; + GPBField* field = [[[GPBField alloc] initWithNumber:1] autorelease]; + [field addVarint:0x7FFFFFFFFFFFFFFFL]; + [fields addField:field]; + + NSData* data = [fields data]; + + GPBUnknownFieldSet* parsed = [[[GPBUnknownFieldSet alloc] init] autorelease]; + [parsed mergeFromData:data]; + GPBField* field2 = [parsed getField:1]; + XCTAssertEqual(field2.varintList.count, (NSUInteger)1); + XCTAssertEqual(0x7FFFFFFFFFFFFFFFULL, [field2.varintList valueAtIndex:0]); +} + +- (void)testMergingFields { + GPBField* field1 = [[[GPBField alloc] initWithNumber:1] autorelease]; + [field1 addVarint:1]; + [field1 addFixed32:2]; + [field1 addFixed64:3]; + [field1 addLengthDelimited:[NSData dataWithBytes:"hello" length:5]]; + [field1 addGroup:[[unknownFields_ copy] autorelease]]; + GPBField* field2 = [[[GPBField alloc] initWithNumber:2] autorelease]; + [field2 mergeFromField:field1]; + XCTAssertEqualObjects(field1, field2); +} + +@end diff --git a/objectivec/Tests/GPBUtilitiesTests.m b/objectivec/Tests/GPBUtilitiesTests.m new file mode 100644 index 00000000..02de0197 --- /dev/null +++ b/objectivec/Tests/GPBUtilitiesTests.m @@ -0,0 +1,363 @@ +// 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. + +#import <XCTest/XCTest.h> + +#import "GPBUtilities_PackagePrivate.h" + +#import <objc/runtime.h> + +#import "GPBTestUtilities.h" + +#import "GPBDescriptor.h" +#import "GPBDescriptor_PackagePrivate.h" +#import "GPBMessage.h" + +#import "google/protobuf/MapUnittest.pbobjc.h" +#import "google/protobuf/Unittest.pbobjc.h" +#import "google/protobuf/UnittestObjc.pbobjc.h" + +@interface UtilitiesTests : GPBTestCase +@end + +// Support code for testing +typedef struct { + uint32_t _has_storage_[1]; + BOOL aBool; + int32_t aInt32; + uint32_t aUInt32; + int64_t aInt64; + uint64_t aUInt64; + float aFloat; + double aDouble; + id aObject; + BOOL _hasTest; + BOOL stopper; + BOOL shouldNotBeCounted; + GPBInt32Array *anArray; +} ApplyFunctionsTest_Storage; + +@interface ApplyFunctionsTest : GPBMessage +@property(nonatomic, readwrite) BOOL aBool; +@property(nonatomic, readwrite) int32_t aInt32; +@property(nonatomic, readwrite) uint32_t aUInt32; +@property(nonatomic, readwrite) int64_t aInt64; +@property(nonatomic, readwrite) uint64_t aUInt64; +@property(nonatomic, readwrite) float aFloat; +@property(nonatomic, readwrite) double aDouble; +@property(nonatomic, readwrite, retain) id aObject; +@property(nonatomic, readwrite) BOOL _hasTest; +@property(nonatomic, readwrite) BOOL stopper; +@property(nonatomic, readwrite) BOOL shouldNotBeCounted; +@property(nonatomic, readwrite, retain) GPBInt32Array *anArray; +@end + +@implementation ApplyFunctionsTest + +@dynamic aBool, aInt32, aUInt32, aInt64, aUInt64, aFloat, aDouble, aObject; +@dynamic _hasTest, stopper, shouldNotBeCounted, anArray; + ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { +#define FIELD_ENTRY(NAME, INDEX) \ + { \ + .name = "a" #NAME, .hasIndex = INDEX, .type = GPBType##NAME, \ + .offset = offsetof(ApplyFunctionsTest_Storage, a##NAME), \ + } + FIELD_ENTRY(Bool, 1), + FIELD_ENTRY(Int32, 2), + FIELD_ENTRY(UInt32, 3), + FIELD_ENTRY(Int64, 4), + FIELD_ENTRY(UInt64, 5), + FIELD_ENTRY(Float, 6), + FIELD_ENTRY(Double, 7), +#undef FIELD_ENTRY + { + .name = "aObject", + .type = GPBTypeString, + .hasIndex = 8, + .offset = offsetof(ApplyFunctionsTest_Storage, aObject), + }, + { + .name = "stopper", + .type = GPBTypeBool, + .hasIndex = 9, + .offset = offsetof(ApplyFunctionsTest_Storage, stopper), + }, + { + .name = "shouldNotBeCounted", + .type = GPBTypeBool, + .hasIndex = 10, + .offset = offsetof(ApplyFunctionsTest_Storage, shouldNotBeCounted), + }, + { + .name = "anArray", + .type = GPBTypeInt32, + .hasIndex = 11, + .flags = GPBFieldRepeated, + .offset = offsetof(ApplyFunctionsTest_Storage, anArray), + }, + }; + descriptor = [GPBDescriptor + allocDescriptorForClass:[self class] + rootClass:Nil + file:nil + fields:fields + fieldCount:sizeof(fields) / + sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:NULL + enumCount:0 + ranges:NULL + rangeCount:0 + storageSize:sizeof(ApplyFunctionsTest_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + +typedef struct { + int calledBool; + int calledInt32; + int calledUInt32; + int calledInt64; + int calledUInt64; + int calledFloat; + int calledDouble; + int calledObject; + int hitCount; +} TestApplyFunctionsContext; + +// Really, who needs templates? +// Macro for testing apply functions. Declares a variety of different functions +// base on |NAME|. +#define TEST_APPLY_FUNCTIONS_FUNC(NAME) \ + static BOOL TestApplyFunction##NAME(GPBFieldDescriptor *field, \ + void *voidContext) { \ + TestApplyFunctionsContext *context = voidContext; \ + if (field->getSel_ == sel_getUid("stopper")) return NO; \ + context->called##NAME += 1; \ + context->hitCount += 1; \ + return YES; \ + } + +TEST_APPLY_FUNCTIONS_FUNC(Bool) +TEST_APPLY_FUNCTIONS_FUNC(Int32) +TEST_APPLY_FUNCTIONS_FUNC(UInt32) +TEST_APPLY_FUNCTIONS_FUNC(Int64) +TEST_APPLY_FUNCTIONS_FUNC(UInt64) +TEST_APPLY_FUNCTIONS_FUNC(Float) +TEST_APPLY_FUNCTIONS_FUNC(Double) +TEST_APPLY_FUNCTIONS_FUNC(Object) + +@implementation UtilitiesTests + +- (void)testRightShiftFunctions { + XCTAssertEqual((1UL << 31) >> 31, 1UL); + XCTAssertEqual((1 << 31) >> 31, -1); + XCTAssertEqual((1ULL << 63) >> 63, 1ULL); + XCTAssertEqual((1LL << 63) >> 63, -1LL); + + XCTAssertEqual(GPBLogicalRightShift32((1 << 31), 31), 1); + XCTAssertEqual(GPBLogicalRightShift64((1LL << 63), 63), 1LL); +} + +- (void)testMutability { + ApplyFunctionsTest *foo_message = [ApplyFunctionsTest message]; + XCTAssertEqual(0, [foo_message aInt32]); + [foo_message setAInt32:100]; + XCTAssertEqual(100, [foo_message aInt32]); +} + +- (void)testSerializedSize { + ApplyFunctionsTest *foo_message = [ApplyFunctionsTest message]; + [foo_message setAInt32:100]; + size_t size1 = [foo_message serializedSize]; + [foo_message setAInt64:100]; + size_t size2 = [foo_message serializedSize]; + + // Intentionally doing a pointer comparison. + XCTAssertNotEqual(size1, size2); +} + +- (void)testCopying { + ApplyFunctionsTest *foo_message = [ApplyFunctionsTest message]; + [foo_message setAInt32:100]; + [foo_message setAObject:@"Happy"]; + ApplyFunctionsTest *foo = [[foo_message copy] autorelease]; + XCTAssertNotEqual(foo, foo_message); // Pointer comparision + XCTAssertEqualObjects(foo, foo_message); +} + +- (void)testApplyFunctions { + // Covers ApplyFunctionsToProtoVariables and + // ApplyFunctionsBasedOnEncodingType. + // This test depends on the layout of the ivars to be in the order + // declared in the interface. If this is not true, it will fail and will + // need to be rewritten to accomodate. + TestApplyFunctionsContext context; + memset(&context, 0, sizeof(context)); + GPBApplyFunctions foo = GPBAPPLY_FUNCTIONS_INIT(TestApplyFunction); + ApplyFunctionsTest *msg = [ApplyFunctionsTest message]; + GPBApplyFunctionsToMessageFields(&foo, msg, &context); + + // Only eight vars should be set. + // "stopper" should cause the loop to quit so it and shouldNotBeCounted should + // not be counted. + // "_hasTest" should be skipped over. + // Each of the vars should only be set once. + XCTAssertEqual(context.hitCount, 8); + XCTAssertEqual(context.calledBool, 1); + XCTAssertEqual(context.calledInt32, 1); + XCTAssertEqual(context.calledUInt32, 1); + XCTAssertEqual(context.calledInt64, 1); + XCTAssertEqual(context.calledUInt64, 1); + XCTAssertEqual(context.calledFloat, 1); + XCTAssertEqual(context.calledDouble, 1); + XCTAssertEqual(context.calledObject, 1); +} + +- (void)testGPBDecodeTextFormatName { + uint8_t decodeData[] = { + 0x6, + // An inlined string (first to make sure the leading null is handled + // correctly, and with a key of zero to check that). + 0x0, 0x0, 'z', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'I', 'J', 0x0, + // All as is (00 op) + 0x1, 0x0A, 0x0, + // Underscore, upper + 9 (10 op) + 0x3, 0xCA, 0x0, + // Upper + 3 (10 op), underscore, upper + 5 (10 op) + 0x2, 0x44, 0xC6, 0x0, + // All Upper for 4 (11 op), underscore, underscore, upper + 5 (10 op), + // underscore, lower + 0 (01 op) + 0x4, 0x64, 0x80, 0xC5, 0xA1, 0x0, + // 2 byte key: as is + 3 (00 op), underscore, lower + 4 (01 op), + // underscore, lower + 3 (01 op), underscore, lower + 1 (01 op), + // underscore, lower + 30 (01 op), as is + 30 (00 op), as is + 13 (00 op), + // underscore, as is + 3 (00 op) + 0xE8, 0x07, 0x04, 0xA5, 0xA4, 0xA2, 0xBF, 0x1F, 0x0E, 0x84, 0x0, + }; + NSString *inputStr = @"abcdefghIJ"; + + // Empty inputs + + XCTAssertNil(GPBDecodeTextFormatName(nil, 1, NULL)); + XCTAssertNil(GPBDecodeTextFormatName(decodeData, 1, NULL)); + XCTAssertNil(GPBDecodeTextFormatName(nil, 1, inputStr)); + + // Keys not found. + + XCTAssertNil(GPBDecodeTextFormatName(decodeData, 5, inputStr)); + XCTAssertNil(GPBDecodeTextFormatName(decodeData, -1, inputStr)); + + // Some name decodes. + + XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 1, inputStr), @"abcdefghIJ"); + XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 2, inputStr), @"Abcd_EfghIJ"); + XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 3, inputStr), @"_AbcdefghIJ"); + XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 4, inputStr), @"ABCD__EfghI_j"); + + // An inlined string (and key of zero). + XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 0, inputStr), @"zbcdefghIJ"); + + // Long name so multiple decode ops are needed. + inputStr = @"longFieldNameIsLooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong1000"; + XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 1000, inputStr), + @"long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_1000"); +} + +- (void)testTextFormat { + TestAllTypes *message = [TestAllTypes message]; + + // Not kGPBDefaultRepeatCount because we are comparing to golden master file + // which was generated with 2. + [self setAllFields:message repeatedCount:2]; + + NSString *result = GPBTextFormatForMessage(message, nil); + + NSString *fileName = @"text_format_unittest_data.txt"; + NSData *resultData = [result dataUsingEncoding:NSUTF8StringEncoding]; + NSData *expectedData = + [self getDataFileNamed:fileName dataToWrite:resultData]; + NSString *expected = [[NSString alloc] initWithData:expectedData + encoding:NSUTF8StringEncoding]; + XCTAssertEqualObjects(expected, result); + [expected release]; +} + +- (void)testTextFormatExtra { + // -testTextFormat uses all protos with fields that don't require special + // handing for figuring out the names. The ObjC proto has a bunch of oddball + // field and enum names that require the decode info to get right, so this + // confirms they generated and decoded correctly. + + self_Class *message = [self_Class message]; + message.cmd = YES; + message.isProxy_p = YES; + message.subEnum = self_autorelease_RetainCount; + message.new_p.copy_p = @"foo"; + + NSString *expected = @"_cmd: true\n" + @"isProxy: true\n" + @"SubEnum: retainCount\n" + @"New {\n" + @" copy: \"foo\"\n" + @"}\n"; + NSString *result = GPBTextFormatForMessage(message, nil); + XCTAssertEqualObjects(expected, result); +} + +- (void)testTextFormatMaps { + TestMap *message = [TestMap message]; + + // Map iteration order doesn't have to be stable, so use only one entry. + [self setAllMapFields:message numEntries:1]; + + NSString *result = GPBTextFormatForMessage(message, nil); + + NSString *fileName = @"text_format_map_unittest_data.txt"; + NSData *resultData = [result dataUsingEncoding:NSUTF8StringEncoding]; + NSData *expectedData = + [self getDataFileNamed:fileName dataToWrite:resultData]; + NSString *expected = [[NSString alloc] initWithData:expectedData + encoding:NSUTF8StringEncoding]; + XCTAssertEqualObjects(expected, result); + [expected release]; +} + +// TODO(thomasvl): add test with extensions once those format with correct names. + +@end diff --git a/objectivec/Tests/GPBWellKnownTypesTest.m b/objectivec/Tests/GPBWellKnownTypesTest.m new file mode 100644 index 00000000..78f4e637 --- /dev/null +++ b/objectivec/Tests/GPBWellKnownTypesTest.m @@ -0,0 +1,102 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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. + +#import "GPBWellKnownTypes.h" + +#import <XCTest/XCTest.h> + +// A basically random interval into the future for testing with. +static const NSTimeInterval kFutureOffsetInterval = 15000; + +// Nanosecond time accuracy +static const NSTimeInterval kTimeAccuracy = 1e-9; + +@interface WellKnownTypesTest : XCTestCase +@end + +@implementation WellKnownTypesTest + +- (void)testTimeStamp { + // Test Creation. + NSDate *date = [NSDate date]; + GPBTimestamp *timeStamp = [[GPBTimestamp alloc] initWithDate:date]; + NSDate *timeStampDate = timeStamp.date; + + // Comparing timeIntervals instead of directly comparing dates because date + // equality requires the time intervals to be exactly the same, and the + // timeintervals go through a bit of floating point error as they are + // converted back and forth from the internal representation. + XCTAssertEqualWithAccuracy(date.timeIntervalSince1970, + timeStampDate.timeIntervalSince1970, + kTimeAccuracy); + + NSTimeInterval time = [date timeIntervalSince1970]; + GPBTimestamp *timeStamp2 = + [[GPBTimestamp alloc] initWithTimeIntervalSince1970:time]; + NSTimeInterval durationTime = timeStamp2.timeIntervalSince1970; + XCTAssertEqualWithAccuracy(time, durationTime, kTimeAccuracy); + [timeStamp release]; + + // Test Mutation. + date = [NSDate dateWithTimeIntervalSinceNow:kFutureOffsetInterval]; + timeStamp2.date = date; + timeStampDate = timeStamp2.date; + XCTAssertEqualWithAccuracy(date.timeIntervalSince1970, + timeStampDate.timeIntervalSince1970, + kTimeAccuracy); + + time = date.timeIntervalSince1970; + timeStamp2.timeIntervalSince1970 = time; + durationTime = timeStamp2.timeIntervalSince1970; + XCTAssertEqualWithAccuracy(time, durationTime, kTimeAccuracy); + [timeStamp2 release]; +} + +- (void)testDuration { + // Test Creation. + NSTimeInterval time = [[NSDate date] timeIntervalSince1970]; + GPBDuration *duration = + [[GPBDuration alloc] initWithTimeIntervalSince1970:time]; + NSTimeInterval durationTime = duration.timeIntervalSince1970; + XCTAssertEqualWithAccuracy(time, durationTime, kTimeAccuracy); + [duration release]; + + // Test Mutation. + GPBDuration *duration2 = + [[GPBDuration alloc] initWithTimeIntervalSince1970:time]; + NSDate *date = [NSDate dateWithTimeIntervalSinceNow:kFutureOffsetInterval]; + time = date.timeIntervalSince1970; + duration2.timeIntervalSince1970 = time; + durationTime = duration2.timeIntervalSince1970; + XCTAssertEqualWithAccuracy(time, durationTime, kTimeAccuracy); + [duration2 release]; +} + +@end diff --git a/objectivec/Tests/GPBWireFormatTests.m b/objectivec/Tests/GPBWireFormatTests.m new file mode 100644 index 00000000..1344af08 --- /dev/null +++ b/objectivec/Tests/GPBWireFormatTests.m @@ -0,0 +1,246 @@ +// 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. + +#import "GPBTestUtilities.h" + +#import "GPBCodedInputStream.h" +#import "GPBMessage_PackagePrivate.h" +#import "GPBField_PackagePrivate.h" +#import "google/protobuf/Unittest.pbobjc.h" +#import "google/protobuf/UnittestMset.pbobjc.h" + +@interface WireFormatTests : GPBTestCase +@end + +@implementation WireFormatTests + +- (void)testSerialization { + TestAllTypes* message = [self allSetRepeatedCount:kGPBDefaultRepeatCount]; + + NSData* rawBytes = message.data; + XCTAssertEqual(message.serializedSize, (size_t)rawBytes.length); + + TestAllTypes* message2 = [TestAllTypes parseFromData:rawBytes]; + + [self assertAllFieldsSet:message2 repeatedCount:kGPBDefaultRepeatCount]; +} + +- (void)testSerializationPacked { + TestPackedTypes* message = + [self packedSetRepeatedCount:kGPBDefaultRepeatCount]; + + NSData* rawBytes = message.data; + XCTAssertEqual(message.serializedSize, (size_t)rawBytes.length); + + TestPackedTypes* message2 = [TestPackedTypes parseFromData:rawBytes]; + + [self assertPackedFieldsSet:message2 repeatedCount:kGPBDefaultRepeatCount]; +} + +- (void)testSerializeExtensions { + // TestAllTypes and TestAllExtensions should have compatible wire formats, + // so if we serealize a TestAllExtensions then parse it as TestAllTypes + // it should work. + + TestAllExtensions* message = + [self allExtensionsSetRepeatedCount:kGPBDefaultRepeatCount]; + NSData* rawBytes = message.data; + XCTAssertEqual(message.serializedSize, (size_t)rawBytes.length); + + TestAllTypes* message2 = [TestAllTypes parseFromData:rawBytes]; + + [self assertAllFieldsSet:message2 repeatedCount:kGPBDefaultRepeatCount]; +} + +- (void)testSerializePackedExtensions { + // TestPackedTypes and TestPackedExtensions should have compatible wire + // formats; check that they serialize to the same string. + TestPackedExtensions* message = + [self packedExtensionsSetRepeatedCount:kGPBDefaultRepeatCount]; + NSData* rawBytes = message.data; + + TestPackedTypes* message2 = + [self packedSetRepeatedCount:kGPBDefaultRepeatCount]; + NSData* rawBytes2 = message2.data; + + XCTAssertEqualObjects(rawBytes, rawBytes2); +} + +- (void)testParseExtensions { + // TestAllTypes and TestAllExtensions should have compatible wire formats, + // so if we serialize a TestAllTypes then parse it as TestAllExtensions + // it should work. + + TestAllTypes* message = [self allSetRepeatedCount:kGPBDefaultRepeatCount]; + NSData* rawBytes = message.data; + + GPBExtensionRegistry* registry = [self extensionRegistry]; + + TestAllExtensions* message2 = + [TestAllExtensions parseFromData:rawBytes extensionRegistry:registry]; + + [self assertAllExtensionsSet:message2 repeatedCount:kGPBDefaultRepeatCount]; +} + + +- (void) testExtensionsSerializedSize { + size_t allSet = [self allSetRepeatedCount:kGPBDefaultRepeatCount].serializedSize; + size_t extensionSet = [self allExtensionsSetRepeatedCount:kGPBDefaultRepeatCount].serializedSize; + XCTAssertEqual(allSet, extensionSet); +} + +- (void)testParsePackedExtensions { + // Ensure that packed extensions can be properly parsed. + TestPackedExtensions* message = + [self packedExtensionsSetRepeatedCount:kGPBDefaultRepeatCount]; + NSData* rawBytes = message.data; + + GPBExtensionRegistry* registry = [self extensionRegistry]; + + TestPackedExtensions* message2 = + [TestPackedExtensions parseFromData:rawBytes extensionRegistry:registry]; + + [self assertPackedExtensionsSet:message2 + repeatedCount:kGPBDefaultRepeatCount]; +} + +const int kUnknownTypeId = 1550055; + +- (void)testSerializeMessageSet { + // Set up a TestMessageSet with two known messages and an unknown one. + TestMessageSet* message_set = [TestMessageSet message]; + [[message_set getExtension:[TestMessageSetExtension1 messageSetExtension]] + setI:123]; + [[message_set getExtension:[TestMessageSetExtension2 messageSetExtension]] + setStr:@"foo"]; + GPBField* unknownField = + [[[GPBField alloc] initWithNumber:kUnknownTypeId] autorelease]; + [unknownField addLengthDelimited:[NSData dataWithBytes:"bar" length:3]]; + GPBUnknownFieldSet* unknownFieldSet = + [[[GPBUnknownFieldSet alloc] init] autorelease]; + [unknownFieldSet addField:unknownField]; + [message_set setUnknownFields:unknownFieldSet]; + + NSData* data = [message_set data]; + + // Parse back using RawMessageSet and check the contents. + RawMessageSet* raw = [RawMessageSet parseFromData:data]; + + XCTAssertEqual([raw.unknownFields countOfFields], (NSUInteger)0); + + XCTAssertEqual(raw.itemArray.count, (NSUInteger)3); + XCTAssertEqual([raw.itemArray[0] typeId], + [TestMessageSetExtension1 messageSetExtension].fieldNumber); + XCTAssertEqual([raw.itemArray[1] typeId], + [TestMessageSetExtension2 messageSetExtension].fieldNumber); + XCTAssertEqual([raw.itemArray[2] typeId], kUnknownTypeId); + + TestMessageSetExtension1* message1 = + [TestMessageSetExtension1 parseFromData:[raw.itemArray[0] message]]; + XCTAssertEqual(message1.i, 123); + + TestMessageSetExtension2* message2 = + [TestMessageSetExtension2 parseFromData:[raw.itemArray[1] message]]; + XCTAssertEqualObjects(message2.str, @"foo"); + + XCTAssertEqualObjects([raw.itemArray[2] message], + [NSData dataWithBytes:"bar" length:3]); +} + +- (void)testParseMessageSet { + // Set up a RawMessageSet with two known messages and an unknown one. + RawMessageSet* raw = [RawMessageSet message]; + + { + RawMessageSet_Item* item = [RawMessageSet_Item message]; + item.typeId = [TestMessageSetExtension1 messageSetExtension].fieldNumber; + TestMessageSetExtension1* message = [TestMessageSetExtension1 message]; + message.i = 123; + item.message = [message data]; + raw.itemArray = [NSMutableArray array]; + [raw.itemArray addObject:item]; + } + + { + RawMessageSet_Item* item = [RawMessageSet_Item message]; + item.typeId = [TestMessageSetExtension2 messageSetExtension].fieldNumber; + TestMessageSetExtension2* message = [TestMessageSetExtension2 message]; + message.str = @"foo"; + item.message = [message data]; + [raw.itemArray addObject:item]; + } + + { + RawMessageSet_Item* item = [RawMessageSet_Item message]; + item.typeId = kUnknownTypeId; + item.message = [NSData dataWithBytes:"bar" length:3]; + [raw.itemArray addObject:item]; + } + + NSData* data = [raw data]; + + // Parse as a TestMessageSet and check the contents. + TestMessageSet* messageSet = + [TestMessageSet parseFromData:data + extensionRegistry:[UnittestMsetRoot extensionRegistry]]; + + XCTAssertEqual( + [[messageSet + getExtension:[TestMessageSetExtension1 messageSetExtension]] i], + 123); + XCTAssertEqualObjects( + [[messageSet + getExtension:[TestMessageSetExtension2 messageSetExtension]] str], + @"foo"); + + XCTAssertEqual([messageSet.unknownFields countOfFields], (NSUInteger)1); + GPBField* unknownField = [messageSet.unknownFields getField:kUnknownTypeId]; + XCTAssertNotNil(unknownField); + XCTAssertEqual(unknownField.lengthDelimitedList.count, (NSUInteger)1); + XCTAssertEqualObjects(unknownField.lengthDelimitedList[0], + [NSData dataWithBytes:"bar" length:3]); +} + +- (void)assertFieldsInOrder:(NSData*)data { + GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data]; + int32_t previousTag = 0; + + while (YES) { + int32_t tag = [input readTag]; + if (tag == 0) { + break; + } + + XCTAssertGreaterThan(tag, previousTag); + [input skipField:tag]; + } +} + +@end diff --git a/objectivec/Tests/UnitTests-Bridging-Header.h b/objectivec/Tests/UnitTests-Bridging-Header.h new file mode 100644 index 00000000..46292fce --- /dev/null +++ b/objectivec/Tests/UnitTests-Bridging-Header.h @@ -0,0 +1,6 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h" +#import "google/protobuf/UnittestRuntimeProto3.pbobjc.h" diff --git a/objectivec/Tests/UnitTests-Info.plist b/objectivec/Tests/UnitTests-Info.plist new file mode 100644 index 00000000..65013556 --- /dev/null +++ b/objectivec/Tests/UnitTests-Info.plist @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>English</string> + <key>CFBundleExecutable</key> + <string>${EXECUTABLE_NAME}</string> + <key>CFBundleIdentifier</key> + <string>com.yourcompany.${PRODUCT_NAME:identifier}</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundlePackageType</key> + <string>BNDL</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>1.0</string> +</dict> +</plist> diff --git a/objectivec/Tests/golden_message b/objectivec/Tests/golden_message Binary files differnew file mode 100644 index 00000000..7bceab41 --- /dev/null +++ b/objectivec/Tests/golden_message diff --git a/objectivec/Tests/golden_packed_fields_message b/objectivec/Tests/golden_packed_fields_message Binary files differnew file mode 100644 index 00000000..7bceab41 --- /dev/null +++ b/objectivec/Tests/golden_packed_fields_message diff --git a/objectivec/Tests/iOSTestHarness/AppDelegate.m b/objectivec/Tests/iOSTestHarness/AppDelegate.m new file mode 100644 index 00000000..8c4a586b --- /dev/null +++ b/objectivec/Tests/iOSTestHarness/AppDelegate.m @@ -0,0 +1,35 @@ +#import <UIKit/UIKit.h> + +@interface AppDelegate : UIResponder <UIApplicationDelegate> +@property (strong, nonatomic) UIWindow *window; +@end + +@implementation AppDelegate + +@synthesize window; + +- (BOOL)application:(UIApplication *)application + didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + #pragma unused (application, launchOptions) + + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + self.window.backgroundColor = [UIColor whiteColor]; + [self.window makeKeyAndVisible]; + self.window.rootViewController = [[UIViewController alloc] init]; + + UILabel *label = + [[UILabel alloc] initWithFrame:CGRectMake(0, 200, CGRectGetWidth(self.window.frame), 40)]; + label.text = @"Protocol Buffer Test Harness"; + label.textAlignment = NSTextAlignmentCenter; + [self.window addSubview:label]; + + return YES; +} + +@end + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/Contents.json b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..ecd3584e --- /dev/null +++ b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,116 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "size" : "57x57", + "idiom" : "iphone", + "filename" : "iPhone6.png", + "scale" : "1x" + }, + { + "size" : "57x57", + "idiom" : "iphone", + "filename" : "iPhone6@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "iPhone7@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "iPhone7@3x.png", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "50x50", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "50x50", + "scale" : "2x" + }, + { + "size" : "72x72", + "idiom" : "ipad", + "filename" : "iPad6.png", + "scale" : "1x" + }, + { + "size" : "72x72", + "idiom" : "ipad", + "filename" : "iPad6@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "iPad7.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "iPad7@2x.png", + "scale" : "2x" + }, + { + "idiom" : "car", + "size" : "120x120", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +}
\ No newline at end of file diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6.png Binary files differnew file mode 100644 index 00000000..43da2ee4 --- /dev/null +++ b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6.png diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6@2x.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6@2x.png Binary files differnew file mode 100644 index 00000000..2ec93704 --- /dev/null +++ b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6@2x.png diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7.png Binary files differnew file mode 100644 index 00000000..aec8bc1b --- /dev/null +++ b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7.png diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7@2x.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7@2x.png Binary files differnew file mode 100644 index 00000000..e39cc3e7 --- /dev/null +++ b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7@2x.png diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6.png Binary files differnew file mode 100644 index 00000000..5572d79f --- /dev/null +++ b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6.png diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6@2x.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6@2x.png Binary files differnew file mode 100644 index 00000000..2424997f --- /dev/null +++ b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6@2x.png diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7@2x.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7@2x.png Binary files differnew file mode 100644 index 00000000..10bfc3cf --- /dev/null +++ b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7@2x.png diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7@3x.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7@3x.png Binary files differnew file mode 100644 index 00000000..8d16f14d --- /dev/null +++ b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7@3x.png diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/LaunchImage.launchimage/Contents.json b/objectivec/Tests/iOSTestHarness/Images.xcassets/LaunchImage.launchimage/Contents.json new file mode 100644 index 00000000..5a296668 --- /dev/null +++ b/objectivec/Tests/iOSTestHarness/Images.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,49 @@ +{ + "images" : [ + { + "orientation" : "portrait", + "idiom" : "ipad", + "minimum-system-version" : "7.0", + "extent" : "full-screen", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "minimum-system-version" : "7.0", + "extent" : "full-screen", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "minimum-system-version" : "7.0", + "extent" : "full-screen", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "minimum-system-version" : "7.0", + "subtype" : "retina4", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "minimum-system-version" : "7.0", + "extent" : "full-screen", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +}
\ No newline at end of file diff --git a/objectivec/Tests/iOSTestHarness/Info.plist b/objectivec/Tests/iOSTestHarness/Info.plist new file mode 100644 index 00000000..31ab1578 --- /dev/null +++ b/objectivec/Tests/iOSTestHarness/Info.plist @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>en</string> + <key>CFBundleDisplayName</key> + <string>${PRODUCT_NAME}</string> + <key>CFBundleExecutable</key> + <string>${EXECUTABLE_NAME}</string> + <key>CFBundleIdentifier</key> + <string>com.google.${PRODUCT_NAME:rfc1034identifier}</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>${PRODUCT_NAME}</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>1.0</string> + <key>LSRequiresIPhoneOS</key> + <true/> + <key>UILaunchStoryboardName</key> + <string>LaunchScreen</string> + <key>UISupportedInterfaceOrientations</key> + <array> + <string>UIInterfaceOrientationPortrait</string> + <string>UIInterfaceOrientationLandscapeLeft</string> + <string>UIInterfaceOrientationLandscapeRight</string> + </array> + <key>UISupportedInterfaceOrientations~ipad</key> + <array> + <string>UIInterfaceOrientationPortrait</string> + <string>UIInterfaceOrientationLandscapeLeft</string> + <string>UIInterfaceOrientationLandscapeRight</string> + <string>UIInterfaceOrientationPortraitUpsideDown</string> + </array> +</dict> +</plist> diff --git a/objectivec/Tests/iOSTestHarness/LaunchScreen.xib b/objectivec/Tests/iOSTestHarness/LaunchScreen.xib new file mode 100644 index 00000000..22204bfe --- /dev/null +++ b/objectivec/Tests/iOSTestHarness/LaunchScreen.xib @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6254" systemVersion="13F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES"> + <dependencies> + <deployment identifier="iOS"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6247"/> + <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/> + </dependencies> + <objects> + <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> + <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> + <view contentMode="scaleToFill" id="iN0-l3-epB"> + <rect key="frame" x="0.0" y="0.0" width="630" height="503"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Protocol Buffer Test Harness" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX"> + <rect key="frame" x="20" y="147" width="591" height="43"/> + <fontDescription key="fontDescription" type="boldSystem" pointSize="36"/> + <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> + <constraints> + <constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="Kid-kn-2rF"/> + <constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/> + <constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/> + </constraints> + <nil key="simulatedStatusBarMetrics"/> + <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/> + <point key="canvasLocation" x="479" y="456.5"/> + </view> + </objects> +</document> diff --git a/objectivec/Tests/iOSTestHarness/en.lproj/InfoPlist.strings b/objectivec/Tests/iOSTestHarness/en.lproj/InfoPlist.strings new file mode 100644 index 00000000..477b28ff --- /dev/null +++ b/objectivec/Tests/iOSTestHarness/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/objectivec/Tests/text_format_map_unittest_data.txt b/objectivec/Tests/text_format_map_unittest_data.txt new file mode 100644 index 00000000..ad1195e2 --- /dev/null +++ b/objectivec/Tests/text_format_map_unittest_data.txt @@ -0,0 +1,70 @@ +map_int32_int32 { + key: 100 + value: 1 +} +map_int64_int64 { + key: 101 + value: 1 +} +map_uint32_uint32 { + key: 102 + value: 1 +} +map_uint64_uint64 { + key: 103 + value: 1 +} +map_sint32_sint32 { + key: 104 + value: 1 +} +map_sint64_sint64 { + key: 105 + value: 1 +} +map_fixed32_fixed32 { + key: 106 + value: 1 +} +map_fixed64_fixed64 { + key: 107 + value: 1 +} +map_sfixed32_sfixed32 { + key: 108 + value: 1 +} +map_sfixed64_sfixed64 { + key: 109 + value: 1 +} +map_int32_float { + key: 110 + value: 1 +} +map_int32_double { + key: 111 + value: 1 +} +map_bool_bool { + key: true + value: false +} +map_string_string { + key: "112" + value: "1" +} +map_int32_bytes { + key: 113 + value: "\001\000\000\000" +} +map_int32_enum { + key: 114 + value: MAP_ENUM_BAZ +} +map_int32_foreign_message { + key: 115 + value { + c: 1 + } +} diff --git a/objectivec/Tests/text_format_unittest_data.txt b/objectivec/Tests/text_format_unittest_data.txt new file mode 100644 index 00000000..d10f1000 --- /dev/null +++ b/objectivec/Tests/text_format_unittest_data.txt @@ -0,0 +1,116 @@ +optional_int32: 101 +optional_int64: 102 +optional_uint32: 103 +optional_uint64: 104 +optional_sint32: 105 +optional_sint64: 106 +optional_fixed32: 107 +optional_fixed64: 108 +optional_sfixed32: 109 +optional_sfixed64: 110 +optional_float: 111 +optional_double: 112 +optional_bool: true +optional_string: "115" +optional_bytes: "\001\000\002\003\000\005" +OptionalGroup { + a: 117 +} +optional_nested_message { + bb: 118 +} +optional_foreign_message { + c: 119 +} +optional_import_message { + d: 120 +} +optional_nested_enum: BAZ +optional_foreign_enum: FOREIGN_BAZ +optional_import_enum: IMPORT_BAZ +optional_string_piece: "124" +optional_cord: "125" +repeated_int32: 201 +repeated_int32: 301 +repeated_int64: 202 +repeated_int64: 302 +repeated_uint32: 203 +repeated_uint32: 303 +repeated_uint64: 204 +repeated_uint64: 304 +repeated_sint32: 205 +repeated_sint32: 305 +repeated_sint64: 206 +repeated_sint64: 306 +repeated_fixed32: 207 +repeated_fixed32: 307 +repeated_fixed64: 208 +repeated_fixed64: 308 +repeated_sfixed32: 209 +repeated_sfixed32: 309 +repeated_sfixed64: 210 +repeated_sfixed64: 310 +repeated_float: 211 +repeated_float: 311 +repeated_double: 212 +repeated_double: 312 +repeated_bool: false +repeated_bool: true +repeated_string: "215" +repeated_string: "315" +repeated_bytes: "\330\000\000\000" +repeated_bytes: "<\001\000\000" +RepeatedGroup { + a: 217 +} +RepeatedGroup { + a: 317 +} +repeated_nested_message { + bb: 218 +} +repeated_nested_message { + bb: 318 +} +repeated_foreign_message { + c: 219 +} +repeated_foreign_message { + c: 319 +} +repeated_import_message { + d: 220 +} +repeated_import_message { + d: 320 +} +repeated_nested_enum: BAZ +repeated_nested_enum: BAR +repeated_foreign_enum: FOREIGN_BAZ +repeated_foreign_enum: FOREIGN_BAR +repeated_import_enum: IMPORT_BAZ +repeated_import_enum: IMPORT_BAR +repeated_string_piece: "224" +repeated_string_piece: "324" +repeated_cord: "225" +repeated_cord: "325" +default_int32: 401 +default_int64: 402 +default_uint32: 403 +default_uint64: 404 +default_sint32: 405 +default_sint64: 406 +default_fixed32: 407 +default_fixed64: 408 +default_sfixed32: 409 +default_sfixed64: 410 +default_float: 411 +default_double: 412 +default_bool: false +default_string: "415" +default_bytes: "\240\001\000\000" +default_nested_enum: FOO +default_foreign_enum: FOREIGN_FOO +default_import_enum: IMPORT_FOO +default_string_piece: "424" +default_cord: "425" diff --git a/objectivec/Tests/unittest_cycle.proto b/objectivec/Tests/unittest_cycle.proto new file mode 100644 index 00000000..5f6f56a1 --- /dev/null +++ b/objectivec/Tests/unittest_cycle.proto @@ -0,0 +1,58 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 Google Inc. All rights reserved. +// +// 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 = "proto2"; + +package protobuf_unittest; + +// Cycles in the Message graph can cause problems for the mutable classes +// since the properties on the mutable class change types. This file just +// needs to generate source, and that source must compile, to ensure the +// generated source works for this sort of case. + +// You can't make a object graph that spans files, so this can only be done +// within a single proto file. + +message CycleFoo { + optional CycleFoo a_foo = 1; + optional CycleBar a_bar = 2; + optional CycleBaz a_baz = 3; +} + +message CycleBar { + optional CycleBar a_bar = 1; + optional CycleBaz a_baz = 2; + optional CycleFoo a_foo = 3; +} + +message CycleBaz { + optional CycleBaz a_baz = 1; + optional CycleFoo a_foo = 2; + optional CycleBar a_bar = 3; +} diff --git a/objectivec/Tests/unittest_filter.proto b/objectivec/Tests/unittest_filter.proto new file mode 100644 index 00000000..1398dfc8 --- /dev/null +++ b/objectivec/Tests/unittest_filter.proto @@ -0,0 +1,71 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2013 Google Inc. All rights reserved. +// +// 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 = "proto2"; + +package protobuf_unittest; + + +message Keep { +} + +message Remove { +} + +message RemoveJustKidding { +} + +message Other { + optional Keep a = 1; + optional Remove b = 2; +} + +enum RemoveEnum { + RemoveValue = 1; +} + +enum KeepEnum { + KeepValue = 1; +} + +message RemoveEnumMessage { + enum KeepEnumInside { + KeepValue = 1; + } + + enum RemoveEnumInside { + RemoveValue = 1; + } + + message KeepNestedInside { + } + + message RemoveNestedInside { + } +} diff --git a/objectivec/Tests/unittest_name_mangling.proto b/objectivec/Tests/unittest_name_mangling.proto new file mode 100644 index 00000000..aadad6d6 --- /dev/null +++ b/objectivec/Tests/unittest_name_mangling.proto @@ -0,0 +1,37 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 Google Inc. All rights reserved. +// +// 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 = "proto2"; + +option objc_class_prefix = "ABC"; + +package protobuf_unittest; + +// TODO(thomasvl): Add tests for the special cases in name mangling. + diff --git a/objectivec/Tests/unittest_objc.proto b/objectivec/Tests/unittest_objc.proto new file mode 100644 index 00000000..d288a30d --- /dev/null +++ b/objectivec/Tests/unittest_objc.proto @@ -0,0 +1,389 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2011 Google Inc. All rights reserved. +// +// 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 = "proto2"; + +import "google/protobuf/unittest.proto"; + +package protobuf_unittest; + +// Using the messages in unittest.proto, setup for recursive cases for testing +// extensions at various depths. +extend TestAllExtensions { + optional TestAllExtensions recursive_extension = 86; +} + +// Recursive message to for testing autocreators at different depths. +message TestRecursiveMessageWithRepeatedField { + optional TestRecursiveMessageWithRepeatedField a = 1; + repeated int32 i = 2; + repeated string str = 3; +} + +// Recursive message and extension to for testing autocreators at different +// depths. +message TestRecursiveExtension { + optional TestRecursiveExtension recursive_sub_message = 1; + repeated int32 repeated_value = 2; + extensions 1000 to max; +} + +extend TestRecursiveExtension { + optional TestRecursiveExtension recursive_message_extension = 1000; +} + +message self { + message super { + optional int32 description = 1; + } + + enum autorelease { + retain = 1; + release = 2; + retainCount = 3; + } + + // Singular + optional bool id = 1; + optional bool _cmd = 2; + optional bool in = 3; + optional bool out = 4; + optional bool inout = 5; + optional bool bycopy = 6; + optional bool byref = 7; + optional bool oneway = 8; + optional bool dealloc = 9; + optional bool zone = 10; + optional bool isProxy = 11; + optional bool copy = 12; + optional bool readonly = 13; + optional bool default = 14; + optional bool assign = 15; + optional bool getter = 16; + optional bool setter = 17; + optional bool weak = 18; + optional bool public = 19; + optional bool case = 20; + + optional autorelease SubEnum = 25; + + optional group New = 50 { + optional string copy = 51; + } + optional group MutableCopy = 60 { + optional int32 extensionRegistry = 61; + } + + extensions 90 to 94; + +} + +enum retain { + count = 4; + initialized = 5; + serializedSize = 6; +} + +// EnumValueShortName: The short names shouldn't get suffixes/prefixes. +enum Foo { + SERIALIZED_SIZE = 1; + SIZE = 2; + OTHER = 3; +} + +// EnumValueShortName: The enum name gets a prefix. +enum Category { + RED = 1; + BLUE = 2; +} + +// EnumValueShortName: Twist case, full name gets PB, but the short names +// should still end up correct. +enum Time { + BASE = 1; + RECORD = 2; + SOMETHING_ELSE = 3; +} + +extend self { + repeated int32 debugDescription = 90 [packed = true]; + repeated int64 finalize = 91 [packed = true]; + repeated uint32 hash = 92 [packed = true]; + repeated uint64 classForCoder = 93 [packed = true]; + repeated sint32 byref = 94 [packed = true]; +} + +// Test handing of fields that start with init* since Xcode 5's ARC support +// doesn't like messages that look like initializers but aren't. +message ObjCInitFoo { + optional string init_val = 11; + optional int32 init_size = 12; + optional self init_self = 13; + + repeated string init_vals = 21; + repeated int32 init_sizes = 22; + repeated self init_selfs = 23; +} + +// Test handling of fields that start with retained names. +message ObjCRetainedFoo { + optional string new_val_lower_complex = 11; + optional string new_Val_upper_complex = 12; + optional string newvalue_lower_no_underscore_complex = 13; + optional string newValue_upper_no_underscore_complex = 14; + + optional int32 new_val_lower_primitive = 15; + optional int32 new_Val_upper_primitive = 16; + optional int32 newvalue_lower_no_underscore_primitive = 17; + optional int32 newValue_upper_no_underscore_primitive = 18; + + optional self new_val_lower_message = 19; + optional self new_Val_upper_message = 20; + optional self newvalue_lower_no_underscore_message = 21; + optional self newValue_upper_no_underscore_message = 22; + + optional Foo new_val_lower_enum = 23; + optional Foo new_Val_upper_enum = 24; + optional Foo newvalue_lower_no_underscore_enum = 25; + optional Foo newValue_upper_no_underscore_enum = 26; + + repeated string new_val_lower_complex_repeated = 111; + repeated string new_Val_upper_complex_repeated = 112; + repeated string newvalue_lower_no_underscore_complex_repeated = 113; + repeated string newValue_upper_no_underscore_complex_repeated = 114; + + repeated int32 new_val_lower_primitive_repeated = 115; + repeated int32 new_Val_upper_primitive_repeated = 116; + repeated int32 newvalue_lower_no_underscore_primitive_repeated = 117; + repeated int32 newValue_upper_no_underscore_primitive_repeated = 118; + + repeated self new_val_lower_message_repeated = 119; + repeated self new_Val_upper_message_repeated = 120; + repeated self newvalue_lower_no_underscore_message_repeated = 121; + repeated self newValue_upper_no_underscore_message_repeated = 122; + + repeated Foo new_val_lower_enum_repeated = 123; + repeated Foo new_Val_upper_enum_repeated = 124; + repeated Foo newvalue_lower_no_underscore_enum_repeated = 125; + repeated Foo newValue_upper_no_underscore_enum_repeated = 126; + + optional string alloc_val_lower_complex = 211; + optional string alloc_Val_upper_complex = 212; + optional string allocvalue_lower_no_underscore_complex = 213; + optional string allocValue_upper_no_underscore_complex = 214; + + optional int32 alloc_val_lower_primitive = 215; + optional int32 alloc_Val_upper_primitive = 216; + optional int32 allocvalue_lower_no_underscore_primitive = 217; + optional int32 allocValue_upper_no_underscore_primitive = 218; + + optional self alloc_val_lower_message = 219; + optional self alloc_Val_upper_message = 220; + optional self allocvalue_lower_no_underscore_message = 221; + optional self allocValue_upper_no_underscore_message = 222; + + optional Foo alloc_val_lower_enum = 223; + optional Foo alloc_Val_upper_enum = 224; + optional Foo allocvalue_lower_no_underscore_enum = 225; + optional Foo allocValue_upper_no_underscore_enum = 226; + + repeated string alloc_val_lower_complex_repeated = 311; + repeated string alloc_Val_upper_complex_repeated = 312; + repeated string allocvalue_lower_no_underscore_complex_repeated = 313; + repeated string allocValue_upper_no_underscore_complex_repeated = 314; + + repeated int32 alloc_val_lower_primitive_repeated = 315; + repeated int32 alloc_Val_upper_primitive_repeated = 316; + repeated int32 allocvalue_lower_no_underscore_primitive_repeated = 317; + repeated int32 allocValue_upper_no_underscore_primitive_repeated = 318; + + repeated self alloc_val_lower_message_repeated = 319; + repeated self alloc_Val_upper_message_repeated = 320; + repeated self allocvalue_lower_no_underscore_message_repeated = 321; + repeated self allocValue_upper_no_underscore_message_repeated = 322; + + repeated Foo alloc_val_lower_enum_repeated = 323; + repeated Foo alloc_Val_upper_enum_repeated = 324; + repeated Foo allocvalue_lower_no_underscore_enum_repeated = 325; + repeated Foo allocValue_upper_no_underscore_enum_repeated = 326; + + optional string copy_val_lower_complex = 411; + optional string copy_Val_upper_complex = 412; + optional string copyvalue_lower_no_underscore_complex = 413; + optional string copyValue_upper_no_underscore_complex = 414; + + optional int32 copy_val_lower_primitive = 415; + optional int32 copy_Val_upper_primitive = 416; + optional int32 copyvalue_lower_no_underscore_primitive = 417; + optional int32 copyValue_upper_no_underscore_primitive = 418; + + optional self copy_val_lower_message = 419; + optional self copy_Val_upper_message = 420; + optional self copyvalue_lower_no_underscore_message = 421; + optional self copyValue_upper_no_underscore_message = 422; + + optional Foo copy_val_lower_enum = 423; + optional Foo copy_Val_upper_enum = 424; + optional Foo copyvalue_lower_no_underscore_enum = 425; + optional Foo copyValue_upper_no_underscore_enum = 426; + + repeated string copy_val_lower_complex_repeated = 511; + repeated string copy_Val_upper_complex_repeated = 512; + repeated string copyvalue_lower_no_underscore_complex_repeated = 513; + repeated string copyValue_upper_no_underscore_complex_repeated = 514; + + repeated int32 copy_val_lower_primitive_repeated = 515; + repeated int32 copy_Val_upper_primitive_repeated = 516; + repeated int32 copyvalue_lower_no_underscore_primitive_repeated = 517; + repeated int32 copyValue_upper_no_underscore_primitive_repeated = 518; + + repeated self copy_val_lower_message_repeated = 519; + repeated self copy_Val_upper_message_repeated = 520; + repeated self copyvalue_lower_no_underscore_message_repeated = 521; + repeated self copyValue_upper_no_underscore_message_repeated = 522; + + repeated Foo copy_val_lower_enum_repeated = 523; + repeated Foo copy_Val_upper_enum_repeated = 524; + repeated Foo copyvalue_lower_no_underscore_enum_repeated = 525; + repeated Foo copyValue_upper_no_underscore_enum_repeated = 526; + + optional string mutableCopy_val_lower_complex = 611; + optional string mutableCopy_Val_upper_complex = 612; + optional string mutableCopyvalue_lower_no_underscore_complex = 613; + optional string mutableCopyValue_upper_no_underscore_complex = 614; + + optional int32 mutableCopy_val_lower_primitive = 615; + optional int32 mutableCopy_Val_upper_primitive = 616; + optional int32 mutableCopyvalue_lower_no_underscore_primitive = 617; + optional int32 mutableCopyValue_upper_no_underscore_primitive = 618; + + optional self mutableCopy_val_lower_message = 619; + optional self mutableCopy_Val_upper_message = 620; + optional self mutableCopyvalue_lower_no_underscore_message = 621; + optional self mutableCopyValue_upper_no_underscore_message = 622; + + optional Foo mutableCopy_val_lower_enum = 623; + optional Foo mutableCopy_Val_upper_enum = 624; + optional Foo mutableCopyvalue_lower_no_underscore_enum = 625; + optional Foo mutableCopyValue_upper_no_underscore_enum = 626; + + repeated string mutableCopy_val_lower_complex_repeated = 711; + repeated string mutableCopy_Val_upper_complex_repeated = 712; + repeated string mutableCopyvalue_lower_no_underscore_complex_repeated = 713; + repeated string mutableCopyValue_upper_no_underscore_complex_repeated = 714; + + repeated int32 mutableCopy_val_lower_primitive_repeated = 715; + repeated int32 mutableCopy_Val_upper_primitive_repeated = 716; + repeated int32 mutableCopyvalue_lower_no_underscore_primitive_repeated = 717; + repeated int32 mutableCopyValue_upper_no_underscore_primitive_repeated = 718; + + repeated self mutableCopy_val_lower_message_repeated = 719; + repeated self mutableCopy_Val_upper_message_repeated = 720; + repeated self mutableCopyvalue_lower_no_underscore_message_repeated = 721; + repeated self mutableCopyValue_upper_no_underscore_message_repeated = 722; + + repeated Foo mutableCopy_val_lower_enum_repeated = 723; + repeated Foo mutableCopy_Val_upper_enum_repeated = 724; + repeated Foo mutableCopyvalue_lower_no_underscore_enum_repeated = 725; + repeated Foo mutableCopyValue_upper_no_underscore_enum_repeated = 726; +} + +// Test handling of fields that are the retained names. +message ObjCRetainedComplex { + optional string new = 1; + optional string alloc = 2; + optional string copy = 3; + optional string mutableCopy = 4; +} + +message ObjCRetainedComplexRepeated { + repeated string new = 1; + repeated string alloc = 2; + repeated string copy = 3; + repeated string mutableCopy = 4; +} + +message ObjCRetainedPrimitive { + optional int32 new = 1; + optional int32 alloc = 2; + optional int32 copy = 3; + optional int32 mutableCopy = 4; +} + +message ObjCRetainedPrimitiveRepeated { + repeated int32 new = 1; + repeated int32 alloc = 2; + repeated int32 copy = 3; + repeated int32 mutableCopy = 4; +} + +message ObjCRetainedMessage { + optional self new = 1; + optional self alloc = 2; + optional self copy = 3; + optional self mutableCopy = 4; +} + +message ObjCRetainedMessageRepeated { + repeated self new = 1; + repeated self alloc = 2; + repeated self copy = 3; + repeated self mutableCopy = 4; +} + +// Test Handling some MacTypes +message Point { + message Rect { + optional int32 TimeValue = 1; + } +} + +// Test some weird defaults that we see in protos. +message ObjcWeirdDefaults { + // Set default values that match the protocol buffer defined defaults to + // confirm hasDefault and the default values are set correctly. + optional string foo = 1 [default = ""]; + optional bytes bar = 2 [default = ""]; +} + +// Used to confirm negative enum values work as expected. +message EnumTestMsg { + enum MyEnum { + ZERO = 0; + ONE = 1; + TWO = 2; + NEG_ONE = -1; + NEG_TWO = -2; + } + optional MyEnum foo = 1; + optional MyEnum bar = 2 [default = ONE]; + optional MyEnum baz = 3 [default = NEG_ONE]; + + repeated MyEnum mumble = 4; +} diff --git a/objectivec/Tests/unittest_runtime_proto2.proto b/objectivec/Tests/unittest_runtime_proto2.proto new file mode 100644 index 00000000..f9fd3c35 --- /dev/null +++ b/objectivec/Tests/unittest_runtime_proto2.proto @@ -0,0 +1,108 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 Google Inc. All rights reserved. +// +// 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 = "proto2"; + +package protobuf_unittest; + +message Message2 { + enum Enum { + FOO = 0; + BAR = 1; + BAZ = 2; + EXTRA_2 = 20; + } + + optional int32 optional_int32 = 1; + optional int64 optional_int64 = 2; + optional uint32 optional_uint32 = 3; + optional uint64 optional_uint64 = 4; + optional sint32 optional_sint32 = 5; + optional sint64 optional_sint64 = 6; + optional fixed32 optional_fixed32 = 7; + optional fixed64 optional_fixed64 = 8; + optional sfixed32 optional_sfixed32 = 9; + optional sfixed64 optional_sfixed64 = 10; + optional float optional_float = 11; + optional double optional_double = 12; + optional bool optional_bool = 13; + optional string optional_string = 14; + optional bytes optional_bytes = 15; + optional group OptionalGroup = 16 { + optional int32 a = 17; + } + optional Message2 optional_message = 18; + optional Enum optional_enum = 19; + + repeated int32 repeated_int32 = 31; + repeated int64 repeated_int64 = 32; + repeated uint32 repeated_uint32 = 33; + repeated uint64 repeated_uint64 = 34; + repeated sint32 repeated_sint32 = 35; + repeated sint64 repeated_sint64 = 36; + repeated fixed32 repeated_fixed32 = 37; + repeated fixed64 repeated_fixed64 = 38; + repeated sfixed32 repeated_sfixed32 = 39; + repeated sfixed64 repeated_sfixed64 = 40; + repeated float repeated_float = 41; + repeated double repeated_double = 42; + repeated bool repeated_bool = 43; + repeated string repeated_string = 44; + repeated bytes repeated_bytes = 45; + repeated group RepeatedGroup = 46 { + optional int32 a = 47; + } + repeated Message2 repeated_message = 48; + repeated Enum repeated_enum = 49; + repeated Enum repeated_packed_enum = 50 [packed=true]; + + oneof o { + int32 oneof_int32 = 51 [default = 100]; + int64 oneof_int64 = 52 [default = 101]; + uint32 oneof_uint32 = 53 [default = 102]; + uint64 oneof_uint64 = 54 [default = 103]; + sint32 oneof_sint32 = 55 [default = 104]; + sint64 oneof_sint64 = 56 [default = 105]; + fixed32 oneof_fixed32 = 57 [default = 106]; + fixed64 oneof_fixed64 = 58 [default = 107]; + sfixed32 oneof_sfixed32 = 59 [default = 108]; + sfixed64 oneof_sfixed64 = 60 [default = 109]; + float oneof_float = 61 [default = 110]; + double oneof_double = 62 [default = 111]; + bool oneof_bool = 63 [default = true]; + string oneof_string = 64 [default = "string"]; + bytes oneof_bytes = 65 [default = "data"]; + group OneofGroup = 66 { + optional int32 a = 67; + optional int32 b = 167; + } + Message2 oneof_message = 68; + Enum oneof_enum = 69 [default = BAZ]; + } +} diff --git a/objectivec/Tests/unittest_runtime_proto3.proto b/objectivec/Tests/unittest_runtime_proto3.proto new file mode 100644 index 00000000..b6a2f4dc --- /dev/null +++ b/objectivec/Tests/unittest_runtime_proto3.proto @@ -0,0 +1,101 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 Google Inc. All rights reserved. +// +// 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 protobuf_unittest; + +message Message3 { + enum Enum { + FOO = 0; + BAR = 1; + BAZ = 2; + EXTRA_3 = 30; + } + + int32 optional_int32 = 1; + int64 optional_int64 = 2; + uint32 optional_uint32 = 3; + uint64 optional_uint64 = 4; + sint32 optional_sint32 = 5; + sint64 optional_sint64 = 6; + fixed32 optional_fixed32 = 7; + fixed64 optional_fixed64 = 8; + sfixed32 optional_sfixed32 = 9; + sfixed64 optional_sfixed64 = 10; + float optional_float = 11; + double optional_double = 12; + bool optional_bool = 13; + string optional_string = 14; + bytes optional_bytes = 15; + // No 'group' in proto3. + Message3 optional_message = 18; + Enum optional_enum = 19; + + repeated int32 repeated_int32 = 31; + repeated int64 repeated_int64 = 32; + repeated uint32 repeated_uint32 = 33; + repeated uint64 repeated_uint64 = 34; + repeated sint32 repeated_sint32 = 35; + repeated sint64 repeated_sint64 = 36; + repeated fixed32 repeated_fixed32 = 37; + repeated fixed64 repeated_fixed64 = 38; + repeated sfixed32 repeated_sfixed32 = 39; + repeated sfixed64 repeated_sfixed64 = 40; + repeated float repeated_float = 41; + repeated double repeated_double = 42; + repeated bool repeated_bool = 43; + repeated string repeated_string = 44; + repeated bytes repeated_bytes = 45; + // No 'group' in proto3. + repeated Message3 repeated_message = 48; + repeated Enum repeated_enum = 49; + repeated Enum repeated_packed_enum = 50 [packed=true]; + + oneof o { + int32 oneof_int32 = 51; + int64 oneof_int64 = 52; + uint32 oneof_uint32 = 53; + uint64 oneof_uint64 = 54; + sint32 oneof_sint32 = 55; + sint64 oneof_sint64 = 56; + fixed32 oneof_fixed32 = 57; + fixed64 oneof_fixed64 = 58; + sfixed32 oneof_sfixed32 = 59; + sfixed64 oneof_sfixed64 = 60; + float oneof_float = 61; + double oneof_double = 62; + bool oneof_bool = 63; + string oneof_string = 64; + bytes oneof_bytes = 65; + // No 'group' in proto3. + Message3 oneof_message = 68; + Enum oneof_enum = 69; + } +} diff --git a/objectivec/google/protobuf/Descriptor.pbobjc.h b/objectivec/google/protobuf/Descriptor.pbobjc.h new file mode 100644 index 00000000..7b11d899 --- /dev/null +++ b/objectivec/google/protobuf/Descriptor.pbobjc.h @@ -0,0 +1,1046 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/descriptor.proto + +#import "GPBProtocolBuffers.h" + +#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000 +#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources. +#endif + +CF_EXTERN_C_BEGIN + +@class GPBDescriptorProto; +@class GPBDescriptorProto_ExtensionRange; +@class GPBEnumDescriptorProto; +@class GPBEnumOptions; +@class GPBEnumValueDescriptorProto; +@class GPBEnumValueOptions; +@class GPBFieldDescriptorProto; +@class GPBFieldOptions; +@class GPBFileDescriptorProto; +@class GPBFileDescriptorSet; +@class GPBFileOptions; +@class GPBMessageOptions; +@class GPBMethodDescriptorProto; +@class GPBMethodOptions; +@class GPBOneofDescriptorProto; +@class GPBServiceDescriptorProto; +@class GPBServiceOptions; +@class GPBSourceCodeInfo; +@class GPBSourceCodeInfo_Location; +@class GPBUninterpretedOption; +@class GPBUninterpretedOption_NamePart; + +#pragma mark - Enum GPBFieldDescriptorProto_Type + +typedef GPB_ENUM(GPBFieldDescriptorProto_Type) { + // 0 is reserved for errors. + // Order is weird for historical reasons. + GPBFieldDescriptorProto_Type_TypeDouble = 1, + GPBFieldDescriptorProto_Type_TypeFloat = 2, + + // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if + // negative values are likely. + GPBFieldDescriptorProto_Type_TypeInt64 = 3, + GPBFieldDescriptorProto_Type_TypeUint64 = 4, + + // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if + // negative values are likely. + GPBFieldDescriptorProto_Type_TypeInt32 = 5, + GPBFieldDescriptorProto_Type_TypeFixed64 = 6, + GPBFieldDescriptorProto_Type_TypeFixed32 = 7, + GPBFieldDescriptorProto_Type_TypeBool = 8, + GPBFieldDescriptorProto_Type_TypeString = 9, + + // Tag-delimited aggregate. + GPBFieldDescriptorProto_Type_TypeGroup = 10, + + // Length-delimited aggregate. + GPBFieldDescriptorProto_Type_TypeMessage = 11, + + // New in version 2. + GPBFieldDescriptorProto_Type_TypeBytes = 12, + GPBFieldDescriptorProto_Type_TypeUint32 = 13, + GPBFieldDescriptorProto_Type_TypeEnum = 14, + GPBFieldDescriptorProto_Type_TypeSfixed32 = 15, + GPBFieldDescriptorProto_Type_TypeSfixed64 = 16, + + // Uses ZigZag encoding. + GPBFieldDescriptorProto_Type_TypeSint32 = 17, + + // Uses ZigZag encoding. + GPBFieldDescriptorProto_Type_TypeSint64 = 18, +}; + +GPBEnumDescriptor *GPBFieldDescriptorProto_Type_EnumDescriptor(void); + +BOOL GPBFieldDescriptorProto_Type_IsValidValue(int32_t value); + +#pragma mark - Enum GPBFieldDescriptorProto_Label + +typedef GPB_ENUM(GPBFieldDescriptorProto_Label) { + // 0 is reserved for errors + GPBFieldDescriptorProto_Label_LabelOptional = 1, + GPBFieldDescriptorProto_Label_LabelRequired = 2, + + // TODO(sanjay): Should we add LABEL_MAP? + GPBFieldDescriptorProto_Label_LabelRepeated = 3, +}; + +GPBEnumDescriptor *GPBFieldDescriptorProto_Label_EnumDescriptor(void); + +BOOL GPBFieldDescriptorProto_Label_IsValidValue(int32_t value); + +#pragma mark - Enum GPBFileOptions_OptimizeMode + +// Generated classes can be optimized for speed or code size. +typedef GPB_ENUM(GPBFileOptions_OptimizeMode) { + // Generate complete code for parsing, serialization, + GPBFileOptions_OptimizeMode_Speed = 1, + + // etc. + GPBFileOptions_OptimizeMode_CodeSize = 2, + + // Generate code using MessageLite and the lite runtime. + GPBFileOptions_OptimizeMode_LiteRuntime = 3, +}; + +GPBEnumDescriptor *GPBFileOptions_OptimizeMode_EnumDescriptor(void); + +BOOL GPBFileOptions_OptimizeMode_IsValidValue(int32_t value); + +#pragma mark - Enum GPBFieldOptions_CType + +typedef GPB_ENUM(GPBFieldOptions_CType) { + // Default mode. + GPBFieldOptions_CType_String = 0, + GPBFieldOptions_CType_Cord = 1, + GPBFieldOptions_CType_StringPiece = 2, +}; + +GPBEnumDescriptor *GPBFieldOptions_CType_EnumDescriptor(void); + +BOOL GPBFieldOptions_CType_IsValidValue(int32_t value); + + +#pragma mark - GPBDescriptorRoot + +@interface GPBDescriptorRoot : GPBRootObject +@end + +#pragma mark - GPBFileDescriptorSet + +typedef GPB_ENUM(GPBFileDescriptorSet_FieldNumber) { + GPBFileDescriptorSet_FieldNumber_FileArray = 1, +}; + +// The protocol compiler can output a FileDescriptorSet containing the .proto +// files it parses. +@interface GPBFileDescriptorSet : GPBMessage + +// |fileArray| contains |GPBFileDescriptorProto| +@property(nonatomic, readwrite, strong) NSMutableArray *fileArray; + +@end + +#pragma mark - GPBFileDescriptorProto + +typedef GPB_ENUM(GPBFileDescriptorProto_FieldNumber) { + GPBFileDescriptorProto_FieldNumber_Name = 1, + GPBFileDescriptorProto_FieldNumber_Package = 2, + GPBFileDescriptorProto_FieldNumber_DependencyArray = 3, + GPBFileDescriptorProto_FieldNumber_MessageTypeArray = 4, + GPBFileDescriptorProto_FieldNumber_EnumTypeArray = 5, + GPBFileDescriptorProto_FieldNumber_ServiceArray = 6, + GPBFileDescriptorProto_FieldNumber_ExtensionArray = 7, + GPBFileDescriptorProto_FieldNumber_Options = 8, + GPBFileDescriptorProto_FieldNumber_SourceCodeInfo = 9, + GPBFileDescriptorProto_FieldNumber_PublicDependencyArray = 10, + GPBFileDescriptorProto_FieldNumber_WeakDependencyArray = 11, + GPBFileDescriptorProto_FieldNumber_Syntax = 12, +}; + +// Describes a complete .proto file. +@interface GPBFileDescriptorProto : GPBMessage + +// file name, relative to root of source tree +@property(nonatomic, readwrite) BOOL hasName; +@property(nonatomic, readwrite, copy) NSString *name; + +// e.g. "foo", "foo.bar", etc. +@property(nonatomic, readwrite) BOOL hasPackage; +@property(nonatomic, readwrite, copy) NSString *package; + +// Names of files imported by this file. +// |dependencyArray| contains |NSString| +@property(nonatomic, readwrite, strong) NSMutableArray *dependencyArray; + +// Indexes of the public imported files in the dependency list above. +@property(nonatomic, readwrite, strong) GPBInt32Array *publicDependencyArray; + +// Indexes of the weak imported files in the dependency list. +// For Google-internal migration only. Do not use. +@property(nonatomic, readwrite, strong) GPBInt32Array *weakDependencyArray; + +// All top-level definitions in this file. +// |messageTypeArray| contains |GPBDescriptorProto| +@property(nonatomic, readwrite, strong) NSMutableArray *messageTypeArray; + +// |enumTypeArray| contains |GPBEnumDescriptorProto| +@property(nonatomic, readwrite, strong) NSMutableArray *enumTypeArray; + +// |serviceArray| contains |GPBServiceDescriptorProto| +@property(nonatomic, readwrite, strong) NSMutableArray *serviceArray; + +// |extensionArray| contains |GPBFieldDescriptorProto| +@property(nonatomic, readwrite, strong) NSMutableArray *extensionArray; + +@property(nonatomic, readwrite) BOOL hasOptions; +@property(nonatomic, readwrite, strong) GPBFileOptions *options; + +// This field contains optional information about the original source code. +// You may safely remove this entire field without harming runtime +// functionality of the descriptors -- the information is needed only by +// development tools. +@property(nonatomic, readwrite) BOOL hasSourceCodeInfo; +@property(nonatomic, readwrite, strong) GPBSourceCodeInfo *sourceCodeInfo; + +// The syntax of the proto file. +// The supported values are "proto2" and "proto3". +@property(nonatomic, readwrite) BOOL hasSyntax; +@property(nonatomic, readwrite, copy) NSString *syntax; + +@end + +#pragma mark - GPBDescriptorProto + +typedef GPB_ENUM(GPBDescriptorProto_FieldNumber) { + GPBDescriptorProto_FieldNumber_Name = 1, + GPBDescriptorProto_FieldNumber_FieldArray = 2, + GPBDescriptorProto_FieldNumber_NestedTypeArray = 3, + GPBDescriptorProto_FieldNumber_EnumTypeArray = 4, + GPBDescriptorProto_FieldNumber_ExtensionRangeArray = 5, + GPBDescriptorProto_FieldNumber_ExtensionArray = 6, + GPBDescriptorProto_FieldNumber_Options = 7, + GPBDescriptorProto_FieldNumber_OneofDeclArray = 8, +}; + +// Describes a message type. +@interface GPBDescriptorProto : GPBMessage + +@property(nonatomic, readwrite) BOOL hasName; +@property(nonatomic, readwrite, copy) NSString *name; + +// |fieldArray| contains |GPBFieldDescriptorProto| +@property(nonatomic, readwrite, strong) NSMutableArray *fieldArray; + +// |extensionArray| contains |GPBFieldDescriptorProto| +@property(nonatomic, readwrite, strong) NSMutableArray *extensionArray; + +// |nestedTypeArray| contains |GPBDescriptorProto| +@property(nonatomic, readwrite, strong) NSMutableArray *nestedTypeArray; + +// |enumTypeArray| contains |GPBEnumDescriptorProto| +@property(nonatomic, readwrite, strong) NSMutableArray *enumTypeArray; + +// |extensionRangeArray| contains |GPBDescriptorProto_ExtensionRange| +@property(nonatomic, readwrite, strong) NSMutableArray *extensionRangeArray; + +// |oneofDeclArray| contains |GPBOneofDescriptorProto| +@property(nonatomic, readwrite, strong) NSMutableArray *oneofDeclArray; + +@property(nonatomic, readwrite) BOOL hasOptions; +@property(nonatomic, readwrite, strong) GPBMessageOptions *options; + +@end + +#pragma mark - GPBDescriptorProto_ExtensionRange + +typedef GPB_ENUM(GPBDescriptorProto_ExtensionRange_FieldNumber) { + GPBDescriptorProto_ExtensionRange_FieldNumber_Start = 1, + GPBDescriptorProto_ExtensionRange_FieldNumber_End = 2, +}; + +@interface GPBDescriptorProto_ExtensionRange : GPBMessage + +@property(nonatomic, readwrite) BOOL hasStart; +@property(nonatomic, readwrite) int32_t start; + +@property(nonatomic, readwrite) BOOL hasEnd; +@property(nonatomic, readwrite) int32_t end; + +@end + +#pragma mark - GPBFieldDescriptorProto + +typedef GPB_ENUM(GPBFieldDescriptorProto_FieldNumber) { + GPBFieldDescriptorProto_FieldNumber_Name = 1, + GPBFieldDescriptorProto_FieldNumber_Extendee = 2, + GPBFieldDescriptorProto_FieldNumber_Number = 3, + GPBFieldDescriptorProto_FieldNumber_Label = 4, + GPBFieldDescriptorProto_FieldNumber_Type = 5, + GPBFieldDescriptorProto_FieldNumber_TypeName = 6, + GPBFieldDescriptorProto_FieldNumber_DefaultValue = 7, + GPBFieldDescriptorProto_FieldNumber_Options = 8, + GPBFieldDescriptorProto_FieldNumber_OneofIndex = 9, +}; + +// Describes a field within a message. +@interface GPBFieldDescriptorProto : GPBMessage + +@property(nonatomic, readwrite) BOOL hasName; +@property(nonatomic, readwrite, copy) NSString *name; + +@property(nonatomic, readwrite) BOOL hasNumber; +@property(nonatomic, readwrite) int32_t number; + +@property(nonatomic, readwrite) BOOL hasLabel; +@property(nonatomic, readwrite) GPBFieldDescriptorProto_Label label; + +// If type_name is set, this need not be set. If both this and type_name +// are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. +@property(nonatomic, readwrite) BOOL hasType; +@property(nonatomic, readwrite) GPBFieldDescriptorProto_Type type; + +// For message and enum types, this is the name of the type. If the name +// starts with a '.', it is fully-qualified. Otherwise, C++-like scoping +// rules are used to find the type (i.e. first the nested types within this +// message are searched, then within the parent, on up to the root +// namespace). +@property(nonatomic, readwrite) BOOL hasTypeName; +@property(nonatomic, readwrite, copy) NSString *typeName; + +// For extensions, this is the name of the type being extended. It is +// resolved in the same manner as type_name. +@property(nonatomic, readwrite) BOOL hasExtendee; +@property(nonatomic, readwrite, copy) NSString *extendee; + +// For numeric types, contains the original text representation of the value. +// For booleans, "true" or "false". +// For strings, contains the default text contents (not escaped in any way). +// For bytes, contains the C escaped value. All bytes >= 128 are escaped. +// TODO(kenton): Base-64 encode? +@property(nonatomic, readwrite) BOOL hasDefaultValue; +@property(nonatomic, readwrite, copy) NSString *defaultValue; + +// If set, gives the index of a oneof in the containing type's oneof_decl +// list. This field is a member of that oneof. +@property(nonatomic, readwrite) BOOL hasOneofIndex; +@property(nonatomic, readwrite) int32_t oneofIndex; + +@property(nonatomic, readwrite) BOOL hasOptions; +@property(nonatomic, readwrite, strong) GPBFieldOptions *options; + +@end + +#pragma mark - GPBOneofDescriptorProto + +typedef GPB_ENUM(GPBOneofDescriptorProto_FieldNumber) { + GPBOneofDescriptorProto_FieldNumber_Name = 1, +}; + +// Describes a oneof. +@interface GPBOneofDescriptorProto : GPBMessage + +@property(nonatomic, readwrite) BOOL hasName; +@property(nonatomic, readwrite, copy) NSString *name; + +@end + +#pragma mark - GPBEnumDescriptorProto + +typedef GPB_ENUM(GPBEnumDescriptorProto_FieldNumber) { + GPBEnumDescriptorProto_FieldNumber_Name = 1, + GPBEnumDescriptorProto_FieldNumber_ValueArray = 2, + GPBEnumDescriptorProto_FieldNumber_Options = 3, +}; + +// Describes an enum type. +@interface GPBEnumDescriptorProto : GPBMessage + +@property(nonatomic, readwrite) BOOL hasName; +@property(nonatomic, readwrite, copy) NSString *name; + +// |valueArray| contains |GPBEnumValueDescriptorProto| +@property(nonatomic, readwrite, strong) NSMutableArray *valueArray; + +@property(nonatomic, readwrite) BOOL hasOptions; +@property(nonatomic, readwrite, strong) GPBEnumOptions *options; + +@end + +#pragma mark - GPBEnumValueDescriptorProto + +typedef GPB_ENUM(GPBEnumValueDescriptorProto_FieldNumber) { + GPBEnumValueDescriptorProto_FieldNumber_Name = 1, + GPBEnumValueDescriptorProto_FieldNumber_Number = 2, + GPBEnumValueDescriptorProto_FieldNumber_Options = 3, +}; + +// Describes a value within an enum. +@interface GPBEnumValueDescriptorProto : GPBMessage + +@property(nonatomic, readwrite) BOOL hasName; +@property(nonatomic, readwrite, copy) NSString *name; + +@property(nonatomic, readwrite) BOOL hasNumber; +@property(nonatomic, readwrite) int32_t number; + +@property(nonatomic, readwrite) BOOL hasOptions; +@property(nonatomic, readwrite, strong) GPBEnumValueOptions *options; + +@end + +#pragma mark - GPBServiceDescriptorProto + +typedef GPB_ENUM(GPBServiceDescriptorProto_FieldNumber) { + GPBServiceDescriptorProto_FieldNumber_Name = 1, + GPBServiceDescriptorProto_FieldNumber_MethodArray = 2, + GPBServiceDescriptorProto_FieldNumber_Options = 3, +}; + +// Describes a service. +@interface GPBServiceDescriptorProto : GPBMessage + +@property(nonatomic, readwrite) BOOL hasName; +@property(nonatomic, readwrite, copy) NSString *name; + +// |methodArray| contains |GPBMethodDescriptorProto| +@property(nonatomic, readwrite, strong) NSMutableArray *methodArray; + +@property(nonatomic, readwrite) BOOL hasOptions; +@property(nonatomic, readwrite, strong) GPBServiceOptions *options; + +@end + +#pragma mark - GPBMethodDescriptorProto + +typedef GPB_ENUM(GPBMethodDescriptorProto_FieldNumber) { + GPBMethodDescriptorProto_FieldNumber_Name = 1, + GPBMethodDescriptorProto_FieldNumber_InputType = 2, + GPBMethodDescriptorProto_FieldNumber_OutputType = 3, + GPBMethodDescriptorProto_FieldNumber_Options = 4, + GPBMethodDescriptorProto_FieldNumber_ClientStreaming = 5, + GPBMethodDescriptorProto_FieldNumber_ServerStreaming = 6, +}; + +// Describes a method of a service. +@interface GPBMethodDescriptorProto : GPBMessage + +@property(nonatomic, readwrite) BOOL hasName; +@property(nonatomic, readwrite, copy) NSString *name; + +// Input and output type names. These are resolved in the same way as +// FieldDescriptorProto.type_name, but must refer to a message type. +@property(nonatomic, readwrite) BOOL hasInputType; +@property(nonatomic, readwrite, copy) NSString *inputType; + +@property(nonatomic, readwrite) BOOL hasOutputType; +@property(nonatomic, readwrite, copy) NSString *outputType; + +@property(nonatomic, readwrite) BOOL hasOptions; +@property(nonatomic, readwrite, strong) GPBMethodOptions *options; + +// Identifies if client streams multiple client messages +@property(nonatomic, readwrite) BOOL hasClientStreaming; +@property(nonatomic, readwrite) BOOL clientStreaming; + +// Identifies if server streams multiple server messages +@property(nonatomic, readwrite) BOOL hasServerStreaming; +@property(nonatomic, readwrite) BOOL serverStreaming; + +@end + +#pragma mark - GPBFileOptions + +typedef GPB_ENUM(GPBFileOptions_FieldNumber) { + GPBFileOptions_FieldNumber_JavaPackage = 1, + GPBFileOptions_FieldNumber_JavaOuterClassname = 8, + GPBFileOptions_FieldNumber_OptimizeFor = 9, + GPBFileOptions_FieldNumber_JavaMultipleFiles = 10, + GPBFileOptions_FieldNumber_GoPackage = 11, + GPBFileOptions_FieldNumber_CcGenericServices = 16, + GPBFileOptions_FieldNumber_JavaGenericServices = 17, + GPBFileOptions_FieldNumber_PyGenericServices = 18, + GPBFileOptions_FieldNumber_JavaGenerateEqualsAndHash = 20, + GPBFileOptions_FieldNumber_Deprecated = 23, + GPBFileOptions_FieldNumber_JavaStringCheckUtf8 = 27, + GPBFileOptions_FieldNumber_CcEnableArenas = 31, + GPBFileOptions_FieldNumber_ObjcClassPrefix = 36, + GPBFileOptions_FieldNumber_UninterpretedOptionArray = 999, +}; + +@interface GPBFileOptions : GPBMessage + +// Sets the Java package where classes generated from this .proto will be +// placed. By default, the proto package is used, but this is often +// inappropriate because proto packages do not normally start with backwards +// domain names. +@property(nonatomic, readwrite) BOOL hasJavaPackage; +@property(nonatomic, readwrite, copy) NSString *javaPackage; + +// If set, all the classes from the .proto file are wrapped in a single +// outer class with the given name. This applies to both Proto1 +// (equivalent to the old "--one_java_file" option) and Proto2 (where +// a .proto always translates to a single class, but you may want to +// explicitly choose the class name). +@property(nonatomic, readwrite) BOOL hasJavaOuterClassname; +@property(nonatomic, readwrite, copy) NSString *javaOuterClassname; + +// If set true, then the Java code generator will generate a separate .java +// file for each top-level message, enum, and service defined in the .proto +// file. Thus, these types will *not* be nested inside the outer class +// named by java_outer_classname. However, the outer class will still be +// generated to contain the file's getDescriptor() method as well as any +// top-level extensions defined in the file. +@property(nonatomic, readwrite) BOOL hasJavaMultipleFiles; +@property(nonatomic, readwrite) BOOL javaMultipleFiles; + +// If set true, then the Java code generator will generate equals() and +// hashCode() methods for all messages defined in the .proto file. +// - In the full runtime, this is purely a speed optimization, as the +// AbstractMessage base class includes reflection-based implementations of +// these methods. +//- In the lite runtime, setting this option changes the semantics of +// equals() and hashCode() to more closely match those of the full runtime; +// the generated methods compute their results based on field values rather +// than object identity. (Implementations should not assume that hashcodes +// will be consistent across runtimes or versions of the protocol compiler.) +@property(nonatomic, readwrite) BOOL hasJavaGenerateEqualsAndHash; +@property(nonatomic, readwrite) BOOL javaGenerateEqualsAndHash; + +// If set true, then the Java2 code generator will generate code that +// throws an exception whenever an attempt is made to assign a non-UTF-8 +// byte sequence to a string field. +// Message reflection will do the same. +// However, an extension field still accepts non-UTF-8 byte sequences. +// This option has no effect on when used with the lite runtime. +@property(nonatomic, readwrite) BOOL hasJavaStringCheckUtf8; +@property(nonatomic, readwrite) BOOL javaStringCheckUtf8; + +@property(nonatomic, readwrite) BOOL hasOptimizeFor; +@property(nonatomic, readwrite) GPBFileOptions_OptimizeMode optimizeFor; + +// Sets the Go package where structs generated from this .proto will be +// placed. If omitted, the Go package will be derived from the following: +// - The basename of the package import path, if provided. +// - Otherwise, the package statement in the .proto file, if present. +// - Otherwise, the basename of the .proto file, without extension. +@property(nonatomic, readwrite) BOOL hasGoPackage; +@property(nonatomic, readwrite, copy) NSString *goPackage; + +// Should generic services be generated in each language? "Generic" services +// are not specific to any particular RPC system. They are generated by the +// main code generators in each language (without additional plugins). +// Generic services were the only kind of service generation supported by +// early versions of google.protobuf. +// +// Generic services are now considered deprecated in favor of using plugins +// that generate code specific to your particular RPC system. Therefore, +// these default to false. Old code which depends on generic services should +// explicitly set them to true. +@property(nonatomic, readwrite) BOOL hasCcGenericServices; +@property(nonatomic, readwrite) BOOL ccGenericServices; + +@property(nonatomic, readwrite) BOOL hasJavaGenericServices; +@property(nonatomic, readwrite) BOOL javaGenericServices; + +@property(nonatomic, readwrite) BOOL hasPyGenericServices; +@property(nonatomic, readwrite) BOOL pyGenericServices; + +// Is this file deprecated? +// Depending on the target platform, this can emit Deprecated annotations +// for everything in the file, or it will be completely ignored; in the very +// least, this is a formalization for deprecating files. +@property(nonatomic, readwrite) BOOL hasDeprecated; +@property(nonatomic, readwrite) BOOL deprecated; + +// Enables the use of arenas for the proto messages in this file. This applies +// only to generated classes for C++. +@property(nonatomic, readwrite) BOOL hasCcEnableArenas; +@property(nonatomic, readwrite) BOOL ccEnableArenas; + +// Sets the objective c class prefix which is prepended to all objective c +// generated classes from this .proto. There is no default. +@property(nonatomic, readwrite) BOOL hasObjcClassPrefix; +@property(nonatomic, readwrite, copy) NSString *objcClassPrefix; + +// The parser stores options it doesn't recognize here. See above. +// |uninterpretedOptionArray| contains |GPBUninterpretedOption| +@property(nonatomic, readwrite, strong) NSMutableArray *uninterpretedOptionArray; + +@end + +#pragma mark - GPBMessageOptions + +typedef GPB_ENUM(GPBMessageOptions_FieldNumber) { + GPBMessageOptions_FieldNumber_MessageSetWireFormat = 1, + GPBMessageOptions_FieldNumber_NoStandardDescriptorAccessor = 2, + GPBMessageOptions_FieldNumber_Deprecated = 3, + GPBMessageOptions_FieldNumber_MapEntry = 7, + GPBMessageOptions_FieldNumber_UninterpretedOptionArray = 999, +}; + +@interface GPBMessageOptions : GPBMessage + +// Set true to use the old proto1 MessageSet wire format for extensions. +// This is provided for backwards-compatibility with the MessageSet wire +// format. You should not use this for any other reason: It's less +// efficient, has fewer features, and is more complicated. +// +// The message must be defined exactly as follows: +// message Foo { +// option message_set_wire_format = true; +// extensions 4 to max; +// } +// Note that the message cannot have any defined fields; MessageSets only +// have extensions. +// +// All extensions of your type must be singular messages; e.g. they cannot +// be int32s, enums, or repeated messages. +// +// Because this is an option, the above two restrictions are not enforced by +// the protocol compiler. +@property(nonatomic, readwrite) BOOL hasMessageSetWireFormat; +@property(nonatomic, readwrite) BOOL messageSetWireFormat; + +// Disables the generation of the standard "descriptor()" accessor, which can +// conflict with a field of the same name. This is meant to make migration +// from proto1 easier; new code should avoid fields named "descriptor". +@property(nonatomic, readwrite) BOOL hasNoStandardDescriptorAccessor; +@property(nonatomic, readwrite) BOOL noStandardDescriptorAccessor; + +// Is this message deprecated? +// Depending on the target platform, this can emit Deprecated annotations +// for the message, or it will be completely ignored; in the very least, +// this is a formalization for deprecating messages. +@property(nonatomic, readwrite) BOOL hasDeprecated; +@property(nonatomic, readwrite) BOOL deprecated; + +// Whether the message is an automatically generated map entry type for the +// maps field. +// +// For maps fields: +// map<KeyType, ValueType> map_field = 1; +// The parsed descriptor looks like: +// message MapFieldEntry { +// option map_entry = true; +// optional KeyType key = 1; +// optional ValueType value = 2; +// } +// repeated MapFieldEntry map_field = 1; +// +// Implementations may choose not to generate the map_entry=true message, but +// use a native map in the target language to hold the keys and values. +// The reflection APIs in such implementions still need to work as +// if the field is a repeated message field. +// +// NOTE: Do not set the option in .proto files. Always use the maps syntax +// instead. The option should only be implicitly set by the proto compiler +// parser. +@property(nonatomic, readwrite) BOOL hasMapEntry; +@property(nonatomic, readwrite) BOOL mapEntry; + +// The parser stores options it doesn't recognize here. See above. +// |uninterpretedOptionArray| contains |GPBUninterpretedOption| +@property(nonatomic, readwrite, strong) NSMutableArray *uninterpretedOptionArray; + +@end + +#pragma mark - GPBFieldOptions + +typedef GPB_ENUM(GPBFieldOptions_FieldNumber) { + GPBFieldOptions_FieldNumber_Ctype = 1, + GPBFieldOptions_FieldNumber_Packed = 2, + GPBFieldOptions_FieldNumber_Deprecated = 3, + GPBFieldOptions_FieldNumber_Lazy = 5, + GPBFieldOptions_FieldNumber_Weak = 10, + GPBFieldOptions_FieldNumber_UninterpretedOptionArray = 999, +}; + +@interface GPBFieldOptions : GPBMessage + +// The ctype option instructs the C++ code generator to use a different +// representation of the field than it normally would. See the specific +// options below. This option is not yet implemented in the open source +// release -- sorry, we'll try to include it in a future version! +@property(nonatomic, readwrite) BOOL hasCtype; +@property(nonatomic, readwrite) GPBFieldOptions_CType ctype; + +// The packed option can be enabled for repeated primitive fields to enable +// a more efficient representation on the wire. Rather than repeatedly +// writing the tag and type for each element, the entire array is encoded as +// a single length-delimited blob. +@property(nonatomic, readwrite) BOOL hasPacked; +@property(nonatomic, readwrite) BOOL packed; + +// Should this field be parsed lazily? Lazy applies only to message-type +// fields. It means that when the outer message is initially parsed, the +// inner message's contents will not be parsed but instead stored in encoded +// form. The inner message will actually be parsed when it is first accessed. +// +// This is only a hint. Implementations are free to choose whether to use +// eager or lazy parsing regardless of the value of this option. However, +// setting this option true suggests that the protocol author believes that +// using lazy parsing on this field is worth the additional bookkeeping +// overhead typically needed to implement it. +// +// This option does not affect the public interface of any generated code; +// all method signatures remain the same. Furthermore, thread-safety of the +// interface is not affected by this option; const methods remain safe to +// call from multiple threads concurrently, while non-const methods continue +// to require exclusive access. +// +// +// Note that implementations may choose not to check required fields within +// a lazy sub-message. That is, calling IsInitialized() on the outher message +// may return true even if the inner message has missing required fields. +// This is necessary because otherwise the inner message would have to be +// parsed in order to perform the check, defeating the purpose of lazy +// parsing. An implementation which chooses not to check required fields +// must be consistent about it. That is, for any particular sub-message, the +// implementation must either *always* check its required fields, or *never* +// check its required fields, regardless of whether or not the message has +// been parsed. +@property(nonatomic, readwrite) BOOL hasLazy; +@property(nonatomic, readwrite) BOOL lazy; + +// Is this field deprecated? +// Depending on the target platform, this can emit Deprecated annotations +// for accessors, or it will be completely ignored; in the very least, this +// is a formalization for deprecating fields. +@property(nonatomic, readwrite) BOOL hasDeprecated; +@property(nonatomic, readwrite) BOOL deprecated; + +// For Google-internal migration only. Do not use. +@property(nonatomic, readwrite) BOOL hasWeak; +@property(nonatomic, readwrite) BOOL weak; + +// The parser stores options it doesn't recognize here. See above. +// |uninterpretedOptionArray| contains |GPBUninterpretedOption| +@property(nonatomic, readwrite, strong) NSMutableArray *uninterpretedOptionArray; + +@end + +#pragma mark - GPBEnumOptions + +typedef GPB_ENUM(GPBEnumOptions_FieldNumber) { + GPBEnumOptions_FieldNumber_AllowAlias = 2, + GPBEnumOptions_FieldNumber_Deprecated = 3, + GPBEnumOptions_FieldNumber_UninterpretedOptionArray = 999, +}; + +@interface GPBEnumOptions : GPBMessage + +// Set this option to true to allow mapping different tag names to the same +// value. +@property(nonatomic, readwrite) BOOL hasAllowAlias; +@property(nonatomic, readwrite) BOOL allowAlias; + +// Is this enum deprecated? +// Depending on the target platform, this can emit Deprecated annotations +// for the enum, or it will be completely ignored; in the very least, this +// is a formalization for deprecating enums. +@property(nonatomic, readwrite) BOOL hasDeprecated; +@property(nonatomic, readwrite) BOOL deprecated; + +// The parser stores options it doesn't recognize here. See above. +// |uninterpretedOptionArray| contains |GPBUninterpretedOption| +@property(nonatomic, readwrite, strong) NSMutableArray *uninterpretedOptionArray; + +@end + +#pragma mark - GPBEnumValueOptions + +typedef GPB_ENUM(GPBEnumValueOptions_FieldNumber) { + GPBEnumValueOptions_FieldNumber_Deprecated = 1, + GPBEnumValueOptions_FieldNumber_UninterpretedOptionArray = 999, +}; + +@interface GPBEnumValueOptions : GPBMessage + +// Is this enum value deprecated? +// Depending on the target platform, this can emit Deprecated annotations +// for the enum value, or it will be completely ignored; in the very least, +// this is a formalization for deprecating enum values. +@property(nonatomic, readwrite) BOOL hasDeprecated; +@property(nonatomic, readwrite) BOOL deprecated; + +// The parser stores options it doesn't recognize here. See above. +// |uninterpretedOptionArray| contains |GPBUninterpretedOption| +@property(nonatomic, readwrite, strong) NSMutableArray *uninterpretedOptionArray; + +@end + +#pragma mark - GPBServiceOptions + +typedef GPB_ENUM(GPBServiceOptions_FieldNumber) { + GPBServiceOptions_FieldNumber_Deprecated = 33, + GPBServiceOptions_FieldNumber_UninterpretedOptionArray = 999, +}; + +@interface GPBServiceOptions : GPBMessage + +// Is this service deprecated? +// Depending on the target platform, this can emit Deprecated annotations +// for the service, or it will be completely ignored; in the very least, +// this is a formalization for deprecating services. +@property(nonatomic, readwrite) BOOL hasDeprecated; +@property(nonatomic, readwrite) BOOL deprecated; + +// The parser stores options it doesn't recognize here. See above. +// |uninterpretedOptionArray| contains |GPBUninterpretedOption| +@property(nonatomic, readwrite, strong) NSMutableArray *uninterpretedOptionArray; + +@end + +#pragma mark - GPBMethodOptions + +typedef GPB_ENUM(GPBMethodOptions_FieldNumber) { + GPBMethodOptions_FieldNumber_Deprecated = 33, + GPBMethodOptions_FieldNumber_UninterpretedOptionArray = 999, +}; + +@interface GPBMethodOptions : GPBMessage + +// Is this method deprecated? +// Depending on the target platform, this can emit Deprecated annotations +// for the method, or it will be completely ignored; in the very least, +// this is a formalization for deprecating methods. +@property(nonatomic, readwrite) BOOL hasDeprecated; +@property(nonatomic, readwrite) BOOL deprecated; + +// The parser stores options it doesn't recognize here. See above. +// |uninterpretedOptionArray| contains |GPBUninterpretedOption| +@property(nonatomic, readwrite, strong) NSMutableArray *uninterpretedOptionArray; + +@end + +#pragma mark - GPBUninterpretedOption + +typedef GPB_ENUM(GPBUninterpretedOption_FieldNumber) { + GPBUninterpretedOption_FieldNumber_NameArray = 2, + GPBUninterpretedOption_FieldNumber_IdentifierValue = 3, + GPBUninterpretedOption_FieldNumber_PositiveIntValue = 4, + GPBUninterpretedOption_FieldNumber_NegativeIntValue = 5, + GPBUninterpretedOption_FieldNumber_DoubleValue = 6, + GPBUninterpretedOption_FieldNumber_StringValue = 7, + GPBUninterpretedOption_FieldNumber_AggregateValue = 8, +}; + +// A message representing a option the parser does not recognize. This only +// appears in options protos created by the compiler::Parser class. +// DescriptorPool resolves these when building Descriptor objects. Therefore, +// options protos in descriptor objects (e.g. returned by Descriptor::options(), +// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions +// in them. +@interface GPBUninterpretedOption : GPBMessage + +// |nameArray| contains |GPBUninterpretedOption_NamePart| +@property(nonatomic, readwrite, strong) NSMutableArray *nameArray; + +// The value of the uninterpreted option, in whatever type the tokenizer +// identified it as during parsing. Exactly one of these should be set. +@property(nonatomic, readwrite) BOOL hasIdentifierValue; +@property(nonatomic, readwrite, copy) NSString *identifierValue; + +@property(nonatomic, readwrite) BOOL hasPositiveIntValue; +@property(nonatomic, readwrite) uint64_t positiveIntValue; + +@property(nonatomic, readwrite) BOOL hasNegativeIntValue; +@property(nonatomic, readwrite) int64_t negativeIntValue; + +@property(nonatomic, readwrite) BOOL hasDoubleValue; +@property(nonatomic, readwrite) double doubleValue; + +@property(nonatomic, readwrite) BOOL hasStringValue; +@property(nonatomic, readwrite, copy) NSData *stringValue; + +@property(nonatomic, readwrite) BOOL hasAggregateValue; +@property(nonatomic, readwrite, copy) NSString *aggregateValue; + +@end + +#pragma mark - GPBUninterpretedOption_NamePart + +typedef GPB_ENUM(GPBUninterpretedOption_NamePart_FieldNumber) { + GPBUninterpretedOption_NamePart_FieldNumber_NamePart = 1, + GPBUninterpretedOption_NamePart_FieldNumber_IsExtension = 2, +}; + +// The name of the uninterpreted option. Each string represents a segment in +// a dot-separated name. is_extension is true iff a segment represents an +// extension (denoted with parentheses in options specs in .proto files). +// E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents +// "foo.(bar.baz).qux". +@interface GPBUninterpretedOption_NamePart : GPBMessage + +@property(nonatomic, readwrite) BOOL hasNamePart; +@property(nonatomic, readwrite, copy) NSString *namePart; + +@property(nonatomic, readwrite) BOOL hasIsExtension; +@property(nonatomic, readwrite) BOOL isExtension; + +@end + +#pragma mark - GPBSourceCodeInfo + +typedef GPB_ENUM(GPBSourceCodeInfo_FieldNumber) { + GPBSourceCodeInfo_FieldNumber_LocationArray = 1, +}; + +// Encapsulates information about the original source file from which a +// FileDescriptorProto was generated. +@interface GPBSourceCodeInfo : GPBMessage + +// A Location identifies a piece of source code in a .proto file which +// corresponds to a particular definition. This information is intended +// to be useful to IDEs, code indexers, documentation generators, and similar +// tools. +// +// For example, say we have a file like: +// message Foo { +// optional string foo = 1; +// } +// Let's look at just the field definition: +// optional string foo = 1; +// ^ ^^ ^^ ^ ^^^ +// a bc de f ghi +// We have the following locations: +// span path represents +// [a,i) [ 4, 0, 2, 0 ] The whole field definition. +// [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). +// [c,d) [ 4, 0, 2, 0, 5 ] The type (string). +// [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). +// [g,h) [ 4, 0, 2, 0, 3 ] The number (1). +// +// Notes: +// - A location may refer to a repeated field itself (i.e. not to any +// particular index within it). This is used whenever a set of elements are +// logically enclosed in a single code segment. For example, an entire +// extend block (possibly containing multiple extension definitions) will +// have an outer location whose path refers to the "extensions" repeated +// field without an index. +// - Multiple locations may have the same path. This happens when a single +// logical declaration is spread out across multiple places. The most +// obvious example is the "extend" block again -- there may be multiple +// extend blocks in the same scope, each of which will have the same path. +// - A location's span is not always a subset of its parent's span. For +// example, the "extendee" of an extension declaration appears at the +// beginning of the "extend" block and is shared by all extensions within +// the block. +// - Just because a location's span is a subset of some other location's span +// does not mean that it is a descendent. For example, a "group" defines +// both a type and a field in a single declaration. Thus, the locations +// corresponding to the type and field and their components will overlap. +// - Code which tries to interpret locations should probably be designed to +// ignore those that it doesn't understand, as more types of locations could +// be recorded in the future. +// |locationArray| contains |GPBSourceCodeInfo_Location| +@property(nonatomic, readwrite, strong) NSMutableArray *locationArray; + +@end + +#pragma mark - GPBSourceCodeInfo_Location + +typedef GPB_ENUM(GPBSourceCodeInfo_Location_FieldNumber) { + GPBSourceCodeInfo_Location_FieldNumber_PathArray = 1, + GPBSourceCodeInfo_Location_FieldNumber_SpanArray = 2, + GPBSourceCodeInfo_Location_FieldNumber_LeadingComments = 3, + GPBSourceCodeInfo_Location_FieldNumber_TrailingComments = 4, + GPBSourceCodeInfo_Location_FieldNumber_LeadingDetachedCommentsArray = 6, +}; + +@interface GPBSourceCodeInfo_Location : GPBMessage + +// Identifies which part of the FileDescriptorProto was defined at this +// location. +// +// Each element is a field number or an index. They form a path from +// the root FileDescriptorProto to the place where the definition. For +// example, this path: +// [ 4, 3, 2, 7, 1 ] +// refers to: +// file.message_type(3) // 4, 3 +// .field(7) // 2, 7 +// .name() // 1 +// This is because FileDescriptorProto.message_type has field number 4: +// repeated DescriptorProto message_type = 4; +// and DescriptorProto.field has field number 2: +// repeated FieldDescriptorProto field = 2; +// and FieldDescriptorProto.name has field number 1: +// optional string name = 1; +// +// Thus, the above path gives the location of a field name. If we removed +// the last element: +// [ 4, 3, 2, 7 ] +// this path refers to the whole field declaration (from the beginning +// of the label to the terminating semicolon). +@property(nonatomic, readwrite, strong) GPBInt32Array *pathArray; + +// Always has exactly three or four elements: start line, start column, +// end line (optional, otherwise assumed same as start line), end column. +// These are packed into a single field for efficiency. Note that line +// and column numbers are zero-based -- typically you will want to add +// 1 to each before displaying to a user. +@property(nonatomic, readwrite, strong) GPBInt32Array *spanArray; + +// If this SourceCodeInfo represents a complete declaration, these are any +// comments appearing before and after the declaration which appear to be +// attached to the declaration. +// +// A series of line comments appearing on consecutive lines, with no other +// tokens appearing on those lines, will be treated as a single comment. +// +// leading_detached_comments will keep paragraphs of comments that appear +// before (but not connected to) the current element. Each paragraph, +// separated by empty lines, will be one comment element in the repeated +// field. +// +// Only the comment content is provided; comment markers (e.g. //) are +// stripped out. For block comments, leading whitespace and an asterisk +// will be stripped from the beginning of each line other than the first. +// Newlines are included in the output. +// +// Examples: +// +// optional int32 foo = 1; // Comment attached to foo. +// // Comment attached to bar. +// optional int32 bar = 2; +// +// optional string baz = 3; +// // Comment attached to baz. +// // Another line attached to baz. +// +// // Comment attached to qux. +// // +// // Another line attached to qux. +// optional double qux = 4; +// +// // Detached comment for corge. This is not leading or trailing comments +// // to qux or corge because there are blank lines separating it from +// // both. +// +// // Detached comment for corge paragraph 2. +// +// optional string corge = 5; +// /* Block comment attached +// * to corge. Leading asterisks +// * will be removed. */ +// /* Block comment attached to +// * grault. */ +// optional int32 grault = 6; +// +// // ignored detached comments. +@property(nonatomic, readwrite) BOOL hasLeadingComments; +@property(nonatomic, readwrite, copy) NSString *leadingComments; + +@property(nonatomic, readwrite) BOOL hasTrailingComments; +@property(nonatomic, readwrite, copy) NSString *trailingComments; + +// |leadingDetachedCommentsArray| contains |NSString| +@property(nonatomic, readwrite, strong) NSMutableArray *leadingDetachedCommentsArray; + +@end + +CF_EXTERN_C_END diff --git a/objectivec/google/protobuf/Descriptor.pbobjc.m b/objectivec/google/protobuf/Descriptor.pbobjc.m new file mode 100644 index 00000000..b7d2e64f --- /dev/null +++ b/objectivec/google/protobuf/Descriptor.pbobjc.m @@ -0,0 +1,2205 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/descriptor.proto + +#import "GPBProtocolBuffers_RuntimeSupport.h" + +#import "google/protobuf/Descriptor.pbobjc.h" + +#pragma mark - GPBDescriptorRoot + +@implementation GPBDescriptorRoot + +@end + +static GPBFileDescriptor *GPBDescriptorRoot_FileDescriptor(void) { + // This is called by +initialize so there is no need to worry + // about thread safety of the singleton. + static GPBFileDescriptor *descriptor = NULL; + if (!descriptor) { + descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" + syntax:GPBFileSyntaxProto2]; + } + return descriptor; +} + +#pragma mark - GPBFileDescriptorSet + +@implementation GPBFileDescriptorSet + +@dynamic fileArray; + +typedef struct GPBFileDescriptorSet_Storage { + uint32_t _has_storage_[1]; + NSMutableArray *fileArray; +} GPBFileDescriptorSet_Storage; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "fileArray", + .number = GPBFileDescriptorSet_FieldNumber_FileArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeMessage, + .offset = offsetof(GPBFileDescriptorSet_Storage, fileArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBFileDescriptorProto), + .fieldOptions = NULL, + }, + }; + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBFileDescriptorSet class] + rootClass:[GPBDescriptorRoot class] + file:GPBDescriptorRoot_FileDescriptor() + fields:fields + fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:NULL + enumCount:0 + ranges:NULL + rangeCount:0 + storageSize:sizeof(GPBFileDescriptorSet_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + +#pragma mark - GPBFileDescriptorProto + +@implementation GPBFileDescriptorProto + +@dynamic hasName, name; +@dynamic hasPackage, package; +@dynamic dependencyArray; +@dynamic publicDependencyArray; +@dynamic weakDependencyArray; +@dynamic messageTypeArray; +@dynamic enumTypeArray; +@dynamic serviceArray; +@dynamic extensionArray; +@dynamic hasOptions, options; +@dynamic hasSourceCodeInfo, sourceCodeInfo; +@dynamic hasSyntax, syntax; + +typedef struct GPBFileDescriptorProto_Storage { + uint32_t _has_storage_[1]; + NSString *name; + NSString *package; + NSMutableArray *dependencyArray; + NSMutableArray *messageTypeArray; + NSMutableArray *enumTypeArray; + NSMutableArray *serviceArray; + NSMutableArray *extensionArray; + GPBFileOptions *options; + GPBSourceCodeInfo *sourceCodeInfo; + GPBInt32Array *publicDependencyArray; + GPBInt32Array *weakDependencyArray; + NSString *syntax; +} GPBFileDescriptorProto_Storage; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "name", + .number = GPBFileDescriptorProto_FieldNumber_Name, + .hasIndex = 0, + .flags = GPBFieldOptional, + .type = GPBTypeString, + .offset = offsetof(GPBFileDescriptorProto_Storage, name), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "package", + .number = GPBFileDescriptorProto_FieldNumber_Package, + .hasIndex = 1, + .flags = GPBFieldOptional, + .type = GPBTypeString, + .offset = offsetof(GPBFileDescriptorProto_Storage, package), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "dependencyArray", + .number = GPBFileDescriptorProto_FieldNumber_DependencyArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeString, + .offset = offsetof(GPBFileDescriptorProto_Storage, dependencyArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "messageTypeArray", + .number = GPBFileDescriptorProto_FieldNumber_MessageTypeArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeMessage, + .offset = offsetof(GPBFileDescriptorProto_Storage, messageTypeArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBDescriptorProto), + .fieldOptions = NULL, + }, + { + .name = "enumTypeArray", + .number = GPBFileDescriptorProto_FieldNumber_EnumTypeArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeMessage, + .offset = offsetof(GPBFileDescriptorProto_Storage, enumTypeArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBEnumDescriptorProto), + .fieldOptions = NULL, + }, + { + .name = "serviceArray", + .number = GPBFileDescriptorProto_FieldNumber_ServiceArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeMessage, + .offset = offsetof(GPBFileDescriptorProto_Storage, serviceArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBServiceDescriptorProto), + .fieldOptions = NULL, + }, + { + .name = "extensionArray", + .number = GPBFileDescriptorProto_FieldNumber_ExtensionArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeMessage, + .offset = offsetof(GPBFileDescriptorProto_Storage, extensionArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBFieldDescriptorProto), + .fieldOptions = NULL, + }, + { + .name = "options", + .number = GPBFileDescriptorProto_FieldNumber_Options, + .hasIndex = 9, + .flags = GPBFieldOptional, + .type = GPBTypeMessage, + .offset = offsetof(GPBFileDescriptorProto_Storage, options), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBFileOptions), + .fieldOptions = NULL, + }, + { + .name = "sourceCodeInfo", + .number = GPBFileDescriptorProto_FieldNumber_SourceCodeInfo, + .hasIndex = 10, + .flags = GPBFieldOptional, + .type = GPBTypeMessage, + .offset = offsetof(GPBFileDescriptorProto_Storage, sourceCodeInfo), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBSourceCodeInfo), + .fieldOptions = NULL, + }, + { + .name = "publicDependencyArray", + .number = GPBFileDescriptorProto_FieldNumber_PublicDependencyArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeInt32, + .offset = offsetof(GPBFileDescriptorProto_Storage, publicDependencyArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "weakDependencyArray", + .number = GPBFileDescriptorProto_FieldNumber_WeakDependencyArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeInt32, + .offset = offsetof(GPBFileDescriptorProto_Storage, weakDependencyArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "syntax", + .number = GPBFileDescriptorProto_FieldNumber_Syntax, + .hasIndex = 11, + .flags = GPBFieldOptional, + .type = GPBTypeString, + .offset = offsetof(GPBFileDescriptorProto_Storage, syntax), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + }; + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBFileDescriptorProto class] + rootClass:[GPBDescriptorRoot class] + file:GPBDescriptorRoot_FileDescriptor() + fields:fields + fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:NULL + enumCount:0 + ranges:NULL + rangeCount:0 + storageSize:sizeof(GPBFileDescriptorProto_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + +#pragma mark - GPBDescriptorProto + +@implementation GPBDescriptorProto + +@dynamic hasName, name; +@dynamic fieldArray; +@dynamic extensionArray; +@dynamic nestedTypeArray; +@dynamic enumTypeArray; +@dynamic extensionRangeArray; +@dynamic oneofDeclArray; +@dynamic hasOptions, options; + +typedef struct GPBDescriptorProto_Storage { + uint32_t _has_storage_[1]; + NSString *name; + NSMutableArray *fieldArray; + NSMutableArray *nestedTypeArray; + NSMutableArray *enumTypeArray; + NSMutableArray *extensionRangeArray; + NSMutableArray *extensionArray; + GPBMessageOptions *options; + NSMutableArray *oneofDeclArray; +} GPBDescriptorProto_Storage; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "name", + .number = GPBDescriptorProto_FieldNumber_Name, + .hasIndex = 0, + .flags = GPBFieldOptional, + .type = GPBTypeString, + .offset = offsetof(GPBDescriptorProto_Storage, name), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "fieldArray", + .number = GPBDescriptorProto_FieldNumber_FieldArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeMessage, + .offset = offsetof(GPBDescriptorProto_Storage, fieldArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBFieldDescriptorProto), + .fieldOptions = NULL, + }, + { + .name = "nestedTypeArray", + .number = GPBDescriptorProto_FieldNumber_NestedTypeArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeMessage, + .offset = offsetof(GPBDescriptorProto_Storage, nestedTypeArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBDescriptorProto), + .fieldOptions = NULL, + }, + { + .name = "enumTypeArray", + .number = GPBDescriptorProto_FieldNumber_EnumTypeArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeMessage, + .offset = offsetof(GPBDescriptorProto_Storage, enumTypeArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBEnumDescriptorProto), + .fieldOptions = NULL, + }, + { + .name = "extensionRangeArray", + .number = GPBDescriptorProto_FieldNumber_ExtensionRangeArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeMessage, + .offset = offsetof(GPBDescriptorProto_Storage, extensionRangeArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBDescriptorProto_ExtensionRange), + .fieldOptions = NULL, + }, + { + .name = "extensionArray", + .number = GPBDescriptorProto_FieldNumber_ExtensionArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeMessage, + .offset = offsetof(GPBDescriptorProto_Storage, extensionArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBFieldDescriptorProto), + .fieldOptions = NULL, + }, + { + .name = "options", + .number = GPBDescriptorProto_FieldNumber_Options, + .hasIndex = 7, + .flags = GPBFieldOptional, + .type = GPBTypeMessage, + .offset = offsetof(GPBDescriptorProto_Storage, options), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBMessageOptions), + .fieldOptions = NULL, + }, + { + .name = "oneofDeclArray", + .number = GPBDescriptorProto_FieldNumber_OneofDeclArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeMessage, + .offset = offsetof(GPBDescriptorProto_Storage, oneofDeclArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBOneofDescriptorProto), + .fieldOptions = NULL, + }, + }; + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBDescriptorProto class] + rootClass:[GPBDescriptorRoot class] + file:GPBDescriptorRoot_FileDescriptor() + fields:fields + fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:NULL + enumCount:0 + ranges:NULL + rangeCount:0 + storageSize:sizeof(GPBDescriptorProto_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + +#pragma mark - GPBDescriptorProto_ExtensionRange + +@implementation GPBDescriptorProto_ExtensionRange + +@dynamic hasStart, start; +@dynamic hasEnd, end; + +typedef struct GPBDescriptorProto_ExtensionRange_Storage { + uint32_t _has_storage_[1]; + int32_t start; + int32_t end; +} GPBDescriptorProto_ExtensionRange_Storage; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "start", + .number = GPBDescriptorProto_ExtensionRange_FieldNumber_Start, + .hasIndex = 0, + .flags = GPBFieldOptional, + .type = GPBTypeInt32, + .offset = offsetof(GPBDescriptorProto_ExtensionRange_Storage, start), + .defaultValue.valueInt32 = 0, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "end", + .number = GPBDescriptorProto_ExtensionRange_FieldNumber_End, + .hasIndex = 1, + .flags = GPBFieldOptional, + .type = GPBTypeInt32, + .offset = offsetof(GPBDescriptorProto_ExtensionRange_Storage, end), + .defaultValue.valueInt32 = 0, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + }; + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBDescriptorProto_ExtensionRange class] + rootClass:[GPBDescriptorRoot class] + file:GPBDescriptorRoot_FileDescriptor() + fields:fields + fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:NULL + enumCount:0 + ranges:NULL + rangeCount:0 + storageSize:sizeof(GPBDescriptorProto_ExtensionRange_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + +#pragma mark - GPBFieldDescriptorProto + +@implementation GPBFieldDescriptorProto + +@dynamic hasName, name; +@dynamic hasNumber, number; +@dynamic hasLabel, label; +@dynamic hasType, type; +@dynamic hasTypeName, typeName; +@dynamic hasExtendee, extendee; +@dynamic hasDefaultValue, defaultValue; +@dynamic hasOneofIndex, oneofIndex; +@dynamic hasOptions, options; + +typedef struct GPBFieldDescriptorProto_Storage { + uint32_t _has_storage_[1]; + int32_t number; + GPBFieldDescriptorProto_Label label; + GPBFieldDescriptorProto_Type type; + int32_t oneofIndex; + NSString *name; + NSString *extendee; + NSString *typeName; + NSString *defaultValue; + GPBFieldOptions *options; +} GPBFieldDescriptorProto_Storage; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "name", + .number = GPBFieldDescriptorProto_FieldNumber_Name, + .hasIndex = 0, + .flags = GPBFieldOptional, + .type = GPBTypeString, + .offset = offsetof(GPBFieldDescriptorProto_Storage, name), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "extendee", + .number = GPBFieldDescriptorProto_FieldNumber_Extendee, + .hasIndex = 5, + .flags = GPBFieldOptional, + .type = GPBTypeString, + .offset = offsetof(GPBFieldDescriptorProto_Storage, extendee), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "number", + .number = GPBFieldDescriptorProto_FieldNumber_Number, + .hasIndex = 1, + .flags = GPBFieldOptional, + .type = GPBTypeInt32, + .offset = offsetof(GPBFieldDescriptorProto_Storage, number), + .defaultValue.valueInt32 = 0, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "label", + .number = GPBFieldDescriptorProto_FieldNumber_Label, + .hasIndex = 2, + .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, + .type = GPBTypeEnum, + .offset = offsetof(GPBFieldDescriptorProto_Storage, label), + .defaultValue.valueEnum = GPBFieldDescriptorProto_Label_LabelOptional, + .typeSpecific.enumDescFunc = GPBFieldDescriptorProto_Label_EnumDescriptor, + .fieldOptions = NULL, + }, + { + .name = "type", + .number = GPBFieldDescriptorProto_FieldNumber_Type, + .hasIndex = 3, + .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, + .type = GPBTypeEnum, + .offset = offsetof(GPBFieldDescriptorProto_Storage, type), + .defaultValue.valueEnum = GPBFieldDescriptorProto_Type_TypeDouble, + .typeSpecific.enumDescFunc = GPBFieldDescriptorProto_Type_EnumDescriptor, + .fieldOptions = NULL, + }, + { + .name = "typeName", + .number = GPBFieldDescriptorProto_FieldNumber_TypeName, + .hasIndex = 4, + .flags = GPBFieldOptional, + .type = GPBTypeString, + .offset = offsetof(GPBFieldDescriptorProto_Storage, typeName), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "defaultValue", + .number = GPBFieldDescriptorProto_FieldNumber_DefaultValue, + .hasIndex = 6, + .flags = GPBFieldOptional, + .type = GPBTypeString, + .offset = offsetof(GPBFieldDescriptorProto_Storage, defaultValue), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "options", + .number = GPBFieldDescriptorProto_FieldNumber_Options, + .hasIndex = 8, + .flags = GPBFieldOptional, + .type = GPBTypeMessage, + .offset = offsetof(GPBFieldDescriptorProto_Storage, options), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBFieldOptions), + .fieldOptions = NULL, + }, + { + .name = "oneofIndex", + .number = GPBFieldDescriptorProto_FieldNumber_OneofIndex, + .hasIndex = 7, + .flags = GPBFieldOptional, + .type = GPBTypeInt32, + .offset = offsetof(GPBFieldDescriptorProto_Storage, oneofIndex), + .defaultValue.valueInt32 = 0, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + }; + static GPBMessageEnumDescription enums[] = { + { .enumDescriptorFunc = GPBFieldDescriptorProto_Type_EnumDescriptor }, + { .enumDescriptorFunc = GPBFieldDescriptorProto_Label_EnumDescriptor }, + }; + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBFieldDescriptorProto class] + rootClass:[GPBDescriptorRoot class] + file:GPBDescriptorRoot_FileDescriptor() + fields:fields + fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:enums + enumCount:sizeof(enums) / sizeof(GPBMessageEnumDescription) + ranges:NULL + rangeCount:0 + storageSize:sizeof(GPBFieldDescriptorProto_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + +#pragma mark - Enum GPBFieldDescriptorProto_Type + +GPBEnumDescriptor *GPBFieldDescriptorProto_Type_EnumDescriptor(void) { + static GPBEnumDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageEnumValueDescription values[] = { + { .name = "TypeDouble", .number = GPBFieldDescriptorProto_Type_TypeDouble }, + { .name = "TypeFloat", .number = GPBFieldDescriptorProto_Type_TypeFloat }, + { .name = "TypeInt64", .number = GPBFieldDescriptorProto_Type_TypeInt64 }, + { .name = "TypeUint64", .number = GPBFieldDescriptorProto_Type_TypeUint64 }, + { .name = "TypeInt32", .number = GPBFieldDescriptorProto_Type_TypeInt32 }, + { .name = "TypeFixed64", .number = GPBFieldDescriptorProto_Type_TypeFixed64 }, + { .name = "TypeFixed32", .number = GPBFieldDescriptorProto_Type_TypeFixed32 }, + { .name = "TypeBool", .number = GPBFieldDescriptorProto_Type_TypeBool }, + { .name = "TypeString", .number = GPBFieldDescriptorProto_Type_TypeString }, + { .name = "TypeGroup", .number = GPBFieldDescriptorProto_Type_TypeGroup }, + { .name = "TypeMessage", .number = GPBFieldDescriptorProto_Type_TypeMessage }, + { .name = "TypeBytes", .number = GPBFieldDescriptorProto_Type_TypeBytes }, + { .name = "TypeUint32", .number = GPBFieldDescriptorProto_Type_TypeUint32 }, + { .name = "TypeEnum", .number = GPBFieldDescriptorProto_Type_TypeEnum }, + { .name = "TypeSfixed32", .number = GPBFieldDescriptorProto_Type_TypeSfixed32 }, + { .name = "TypeSfixed64", .number = GPBFieldDescriptorProto_Type_TypeSfixed64 }, + { .name = "TypeSint32", .number = GPBFieldDescriptorProto_Type_TypeSint32 }, + { .name = "TypeSint64", .number = GPBFieldDescriptorProto_Type_TypeSint64 }, + }; + descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBFieldDescriptorProto_Type) + values:values + valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription) + enumVerifier:GPBFieldDescriptorProto_Type_IsValidValue]; + } + return descriptor; +} + +BOOL GPBFieldDescriptorProto_Type_IsValidValue(int32_t value__) { + switch (value__) { + case GPBFieldDescriptorProto_Type_TypeDouble: + case GPBFieldDescriptorProto_Type_TypeFloat: + case GPBFieldDescriptorProto_Type_TypeInt64: + case GPBFieldDescriptorProto_Type_TypeUint64: + case GPBFieldDescriptorProto_Type_TypeInt32: + case GPBFieldDescriptorProto_Type_TypeFixed64: + case GPBFieldDescriptorProto_Type_TypeFixed32: + case GPBFieldDescriptorProto_Type_TypeBool: + case GPBFieldDescriptorProto_Type_TypeString: + case GPBFieldDescriptorProto_Type_TypeGroup: + case GPBFieldDescriptorProto_Type_TypeMessage: + case GPBFieldDescriptorProto_Type_TypeBytes: + case GPBFieldDescriptorProto_Type_TypeUint32: + case GPBFieldDescriptorProto_Type_TypeEnum: + case GPBFieldDescriptorProto_Type_TypeSfixed32: + case GPBFieldDescriptorProto_Type_TypeSfixed64: + case GPBFieldDescriptorProto_Type_TypeSint32: + case GPBFieldDescriptorProto_Type_TypeSint64: + return YES; + default: + return NO; + } +} + +#pragma mark - Enum GPBFieldDescriptorProto_Label + +GPBEnumDescriptor *GPBFieldDescriptorProto_Label_EnumDescriptor(void) { + static GPBEnumDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageEnumValueDescription values[] = { + { .name = "LabelOptional", .number = GPBFieldDescriptorProto_Label_LabelOptional }, + { .name = "LabelRequired", .number = GPBFieldDescriptorProto_Label_LabelRequired }, + { .name = "LabelRepeated", .number = GPBFieldDescriptorProto_Label_LabelRepeated }, + }; + descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBFieldDescriptorProto_Label) + values:values + valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription) + enumVerifier:GPBFieldDescriptorProto_Label_IsValidValue]; + } + return descriptor; +} + +BOOL GPBFieldDescriptorProto_Label_IsValidValue(int32_t value__) { + switch (value__) { + case GPBFieldDescriptorProto_Label_LabelOptional: + case GPBFieldDescriptorProto_Label_LabelRequired: + case GPBFieldDescriptorProto_Label_LabelRepeated: + return YES; + default: + return NO; + } +} + +#pragma mark - GPBOneofDescriptorProto + +@implementation GPBOneofDescriptorProto + +@dynamic hasName, name; + +typedef struct GPBOneofDescriptorProto_Storage { + uint32_t _has_storage_[1]; + NSString *name; +} GPBOneofDescriptorProto_Storage; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "name", + .number = GPBOneofDescriptorProto_FieldNumber_Name, + .hasIndex = 0, + .flags = GPBFieldOptional, + .type = GPBTypeString, + .offset = offsetof(GPBOneofDescriptorProto_Storage, name), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + }; + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBOneofDescriptorProto class] + rootClass:[GPBDescriptorRoot class] + file:GPBDescriptorRoot_FileDescriptor() + fields:fields + fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:NULL + enumCount:0 + ranges:NULL + rangeCount:0 + storageSize:sizeof(GPBOneofDescriptorProto_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + +#pragma mark - GPBEnumDescriptorProto + +@implementation GPBEnumDescriptorProto + +@dynamic hasName, name; +@dynamic valueArray; +@dynamic hasOptions, options; + +typedef struct GPBEnumDescriptorProto_Storage { + uint32_t _has_storage_[1]; + NSString *name; + NSMutableArray *valueArray; + GPBEnumOptions *options; +} GPBEnumDescriptorProto_Storage; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "name", + .number = GPBEnumDescriptorProto_FieldNumber_Name, + .hasIndex = 0, + .flags = GPBFieldOptional, + .type = GPBTypeString, + .offset = offsetof(GPBEnumDescriptorProto_Storage, name), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "valueArray", + .number = GPBEnumDescriptorProto_FieldNumber_ValueArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeMessage, + .offset = offsetof(GPBEnumDescriptorProto_Storage, valueArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBEnumValueDescriptorProto), + .fieldOptions = NULL, + }, + { + .name = "options", + .number = GPBEnumDescriptorProto_FieldNumber_Options, + .hasIndex = 2, + .flags = GPBFieldOptional, + .type = GPBTypeMessage, + .offset = offsetof(GPBEnumDescriptorProto_Storage, options), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBEnumOptions), + .fieldOptions = NULL, + }, + }; + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBEnumDescriptorProto class] + rootClass:[GPBDescriptorRoot class] + file:GPBDescriptorRoot_FileDescriptor() + fields:fields + fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:NULL + enumCount:0 + ranges:NULL + rangeCount:0 + storageSize:sizeof(GPBEnumDescriptorProto_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + +#pragma mark - GPBEnumValueDescriptorProto + +@implementation GPBEnumValueDescriptorProto + +@dynamic hasName, name; +@dynamic hasNumber, number; +@dynamic hasOptions, options; + +typedef struct GPBEnumValueDescriptorProto_Storage { + uint32_t _has_storage_[1]; + int32_t number; + NSString *name; + GPBEnumValueOptions *options; +} GPBEnumValueDescriptorProto_Storage; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "name", + .number = GPBEnumValueDescriptorProto_FieldNumber_Name, + .hasIndex = 0, + .flags = GPBFieldOptional, + .type = GPBTypeString, + .offset = offsetof(GPBEnumValueDescriptorProto_Storage, name), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "number", + .number = GPBEnumValueDescriptorProto_FieldNumber_Number, + .hasIndex = 1, + .flags = GPBFieldOptional, + .type = GPBTypeInt32, + .offset = offsetof(GPBEnumValueDescriptorProto_Storage, number), + .defaultValue.valueInt32 = 0, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "options", + .number = GPBEnumValueDescriptorProto_FieldNumber_Options, + .hasIndex = 2, + .flags = GPBFieldOptional, + .type = GPBTypeMessage, + .offset = offsetof(GPBEnumValueDescriptorProto_Storage, options), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBEnumValueOptions), + .fieldOptions = NULL, + }, + }; + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBEnumValueDescriptorProto class] + rootClass:[GPBDescriptorRoot class] + file:GPBDescriptorRoot_FileDescriptor() + fields:fields + fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:NULL + enumCount:0 + ranges:NULL + rangeCount:0 + storageSize:sizeof(GPBEnumValueDescriptorProto_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + +#pragma mark - GPBServiceDescriptorProto + +@implementation GPBServiceDescriptorProto + +@dynamic hasName, name; +@dynamic methodArray; +@dynamic hasOptions, options; + +typedef struct GPBServiceDescriptorProto_Storage { + uint32_t _has_storage_[1]; + NSString *name; + NSMutableArray *methodArray; + GPBServiceOptions *options; +} GPBServiceDescriptorProto_Storage; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "name", + .number = GPBServiceDescriptorProto_FieldNumber_Name, + .hasIndex = 0, + .flags = GPBFieldOptional, + .type = GPBTypeString, + .offset = offsetof(GPBServiceDescriptorProto_Storage, name), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "methodArray", + .number = GPBServiceDescriptorProto_FieldNumber_MethodArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeMessage, + .offset = offsetof(GPBServiceDescriptorProto_Storage, methodArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBMethodDescriptorProto), + .fieldOptions = NULL, + }, + { + .name = "options", + .number = GPBServiceDescriptorProto_FieldNumber_Options, + .hasIndex = 2, + .flags = GPBFieldOptional, + .type = GPBTypeMessage, + .offset = offsetof(GPBServiceDescriptorProto_Storage, options), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBServiceOptions), + .fieldOptions = NULL, + }, + }; + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBServiceDescriptorProto class] + rootClass:[GPBDescriptorRoot class] + file:GPBDescriptorRoot_FileDescriptor() + fields:fields + fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:NULL + enumCount:0 + ranges:NULL + rangeCount:0 + storageSize:sizeof(GPBServiceDescriptorProto_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + +#pragma mark - GPBMethodDescriptorProto + +@implementation GPBMethodDescriptorProto + +@dynamic hasName, name; +@dynamic hasInputType, inputType; +@dynamic hasOutputType, outputType; +@dynamic hasOptions, options; +@dynamic hasClientStreaming, clientStreaming; +@dynamic hasServerStreaming, serverStreaming; + +typedef struct GPBMethodDescriptorProto_Storage { + uint32_t _has_storage_[1]; + BOOL clientStreaming; + BOOL serverStreaming; + NSString *name; + NSString *inputType; + NSString *outputType; + GPBMethodOptions *options; +} GPBMethodDescriptorProto_Storage; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "name", + .number = GPBMethodDescriptorProto_FieldNumber_Name, + .hasIndex = 0, + .flags = GPBFieldOptional, + .type = GPBTypeString, + .offset = offsetof(GPBMethodDescriptorProto_Storage, name), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "inputType", + .number = GPBMethodDescriptorProto_FieldNumber_InputType, + .hasIndex = 1, + .flags = GPBFieldOptional, + .type = GPBTypeString, + .offset = offsetof(GPBMethodDescriptorProto_Storage, inputType), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "outputType", + .number = GPBMethodDescriptorProto_FieldNumber_OutputType, + .hasIndex = 2, + .flags = GPBFieldOptional, + .type = GPBTypeString, + .offset = offsetof(GPBMethodDescriptorProto_Storage, outputType), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "options", + .number = GPBMethodDescriptorProto_FieldNumber_Options, + .hasIndex = 3, + .flags = GPBFieldOptional, + .type = GPBTypeMessage, + .offset = offsetof(GPBMethodDescriptorProto_Storage, options), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBMethodOptions), + .fieldOptions = NULL, + }, + { + .name = "clientStreaming", + .number = GPBMethodDescriptorProto_FieldNumber_ClientStreaming, + .hasIndex = 4, + .flags = GPBFieldOptional | GPBFieldHasDefaultValue, + .type = GPBTypeBool, + .offset = offsetof(GPBMethodDescriptorProto_Storage, clientStreaming), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "serverStreaming", + .number = GPBMethodDescriptorProto_FieldNumber_ServerStreaming, + .hasIndex = 5, + .flags = GPBFieldOptional | GPBFieldHasDefaultValue, + .type = GPBTypeBool, + .offset = offsetof(GPBMethodDescriptorProto_Storage, serverStreaming), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + }; + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBMethodDescriptorProto class] + rootClass:[GPBDescriptorRoot class] + file:GPBDescriptorRoot_FileDescriptor() + fields:fields + fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:NULL + enumCount:0 + ranges:NULL + rangeCount:0 + storageSize:sizeof(GPBMethodDescriptorProto_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + +#pragma mark - GPBFileOptions + +@implementation GPBFileOptions + +@dynamic hasJavaPackage, javaPackage; +@dynamic hasJavaOuterClassname, javaOuterClassname; +@dynamic hasJavaMultipleFiles, javaMultipleFiles; +@dynamic hasJavaGenerateEqualsAndHash, javaGenerateEqualsAndHash; +@dynamic hasJavaStringCheckUtf8, javaStringCheckUtf8; +@dynamic hasOptimizeFor, optimizeFor; +@dynamic hasGoPackage, goPackage; +@dynamic hasCcGenericServices, ccGenericServices; +@dynamic hasJavaGenericServices, javaGenericServices; +@dynamic hasPyGenericServices, pyGenericServices; +@dynamic hasDeprecated, deprecated; +@dynamic hasCcEnableArenas, ccEnableArenas; +@dynamic hasObjcClassPrefix, objcClassPrefix; +@dynamic uninterpretedOptionArray; + +typedef struct GPBFileOptions_Storage { + uint32_t _has_storage_[1]; + BOOL javaMultipleFiles; + BOOL ccGenericServices; + BOOL javaGenericServices; + BOOL pyGenericServices; + BOOL javaGenerateEqualsAndHash; + BOOL deprecated; + BOOL javaStringCheckUtf8; + BOOL ccEnableArenas; + GPBFileOptions_OptimizeMode optimizeFor; + NSString *javaPackage; + NSString *javaOuterClassname; + NSString *goPackage; + NSString *objcClassPrefix; + NSMutableArray *uninterpretedOptionArray; +} GPBFileOptions_Storage; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "javaPackage", + .number = GPBFileOptions_FieldNumber_JavaPackage, + .hasIndex = 0, + .flags = GPBFieldOptional, + .type = GPBTypeString, + .offset = offsetof(GPBFileOptions_Storage, javaPackage), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "javaOuterClassname", + .number = GPBFileOptions_FieldNumber_JavaOuterClassname, + .hasIndex = 1, + .flags = GPBFieldOptional, + .type = GPBTypeString, + .offset = offsetof(GPBFileOptions_Storage, javaOuterClassname), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "optimizeFor", + .number = GPBFileOptions_FieldNumber_OptimizeFor, + .hasIndex = 5, + .flags = GPBFieldOptional | GPBFieldHasDefaultValue | GPBFieldHasEnumDescriptor, + .type = GPBTypeEnum, + .offset = offsetof(GPBFileOptions_Storage, optimizeFor), + .defaultValue.valueEnum = GPBFileOptions_OptimizeMode_Speed, + .typeSpecific.enumDescFunc = GPBFileOptions_OptimizeMode_EnumDescriptor, + .fieldOptions = NULL, + }, + { + .name = "javaMultipleFiles", + .number = GPBFileOptions_FieldNumber_JavaMultipleFiles, + .hasIndex = 2, + .flags = GPBFieldOptional | GPBFieldHasDefaultValue, + .type = GPBTypeBool, + .offset = offsetof(GPBFileOptions_Storage, javaMultipleFiles), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "goPackage", + .number = GPBFileOptions_FieldNumber_GoPackage, + .hasIndex = 6, + .flags = GPBFieldOptional, + .type = GPBTypeString, + .offset = offsetof(GPBFileOptions_Storage, goPackage), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "ccGenericServices", + .number = GPBFileOptions_FieldNumber_CcGenericServices, + .hasIndex = 7, + .flags = GPBFieldOptional | GPBFieldHasDefaultValue, + .type = GPBTypeBool, + .offset = offsetof(GPBFileOptions_Storage, ccGenericServices), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "javaGenericServices", + .number = GPBFileOptions_FieldNumber_JavaGenericServices, + .hasIndex = 8, + .flags = GPBFieldOptional | GPBFieldHasDefaultValue, + .type = GPBTypeBool, + .offset = offsetof(GPBFileOptions_Storage, javaGenericServices), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "pyGenericServices", + .number = GPBFileOptions_FieldNumber_PyGenericServices, + .hasIndex = 9, + .flags = GPBFieldOptional | GPBFieldHasDefaultValue, + .type = GPBTypeBool, + .offset = offsetof(GPBFileOptions_Storage, pyGenericServices), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "javaGenerateEqualsAndHash", + .number = GPBFileOptions_FieldNumber_JavaGenerateEqualsAndHash, + .hasIndex = 3, + .flags = GPBFieldOptional | GPBFieldHasDefaultValue, + .type = GPBTypeBool, + .offset = offsetof(GPBFileOptions_Storage, javaGenerateEqualsAndHash), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "deprecated", + .number = GPBFileOptions_FieldNumber_Deprecated, + .hasIndex = 10, + .flags = GPBFieldOptional | GPBFieldHasDefaultValue, + .type = GPBTypeBool, + .offset = offsetof(GPBFileOptions_Storage, deprecated), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "javaStringCheckUtf8", + .number = GPBFileOptions_FieldNumber_JavaStringCheckUtf8, + .hasIndex = 4, + .flags = GPBFieldOptional | GPBFieldHasDefaultValue, + .type = GPBTypeBool, + .offset = offsetof(GPBFileOptions_Storage, javaStringCheckUtf8), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "ccEnableArenas", + .number = GPBFileOptions_FieldNumber_CcEnableArenas, + .hasIndex = 11, + .flags = GPBFieldOptional | GPBFieldHasDefaultValue, + .type = GPBTypeBool, + .offset = offsetof(GPBFileOptions_Storage, ccEnableArenas), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "objcClassPrefix", + .number = GPBFileOptions_FieldNumber_ObjcClassPrefix, + .hasIndex = 12, + .flags = GPBFieldOptional, + .type = GPBTypeString, + .offset = offsetof(GPBFileOptions_Storage, objcClassPrefix), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "uninterpretedOptionArray", + .number = GPBFileOptions_FieldNumber_UninterpretedOptionArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeMessage, + .offset = offsetof(GPBFileOptions_Storage, uninterpretedOptionArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption), + .fieldOptions = NULL, + }, + }; + static GPBMessageEnumDescription enums[] = { + { .enumDescriptorFunc = GPBFileOptions_OptimizeMode_EnumDescriptor }, + }; + static GPBExtensionRange ranges[] = { + { .start = 1000, .end = 536870912 }, + }; + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBFileOptions class] + rootClass:[GPBDescriptorRoot class] + file:GPBDescriptorRoot_FileDescriptor() + fields:fields + fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:enums + enumCount:sizeof(enums) / sizeof(GPBMessageEnumDescription) + ranges:ranges + rangeCount:sizeof(ranges) / sizeof(GPBExtensionRange) + storageSize:sizeof(GPBFileOptions_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + +#pragma mark - Enum GPBFileOptions_OptimizeMode + +GPBEnumDescriptor *GPBFileOptions_OptimizeMode_EnumDescriptor(void) { + static GPBEnumDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageEnumValueDescription values[] = { + { .name = "Speed", .number = GPBFileOptions_OptimizeMode_Speed }, + { .name = "CodeSize", .number = GPBFileOptions_OptimizeMode_CodeSize }, + { .name = "LiteRuntime", .number = GPBFileOptions_OptimizeMode_LiteRuntime }, + }; + descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBFileOptions_OptimizeMode) + values:values + valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription) + enumVerifier:GPBFileOptions_OptimizeMode_IsValidValue]; + } + return descriptor; +} + +BOOL GPBFileOptions_OptimizeMode_IsValidValue(int32_t value__) { + switch (value__) { + case GPBFileOptions_OptimizeMode_Speed: + case GPBFileOptions_OptimizeMode_CodeSize: + case GPBFileOptions_OptimizeMode_LiteRuntime: + return YES; + default: + return NO; + } +} + +#pragma mark - GPBMessageOptions + +@implementation GPBMessageOptions + +@dynamic hasMessageSetWireFormat, messageSetWireFormat; +@dynamic hasNoStandardDescriptorAccessor, noStandardDescriptorAccessor; +@dynamic hasDeprecated, deprecated; +@dynamic hasMapEntry, mapEntry; +@dynamic uninterpretedOptionArray; + +typedef struct GPBMessageOptions_Storage { + uint32_t _has_storage_[1]; + BOOL messageSetWireFormat; + BOOL noStandardDescriptorAccessor; + BOOL deprecated; + BOOL mapEntry; + NSMutableArray *uninterpretedOptionArray; +} GPBMessageOptions_Storage; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "messageSetWireFormat", + .number = GPBMessageOptions_FieldNumber_MessageSetWireFormat, + .hasIndex = 0, + .flags = GPBFieldOptional | GPBFieldHasDefaultValue, + .type = GPBTypeBool, + .offset = offsetof(GPBMessageOptions_Storage, messageSetWireFormat), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "noStandardDescriptorAccessor", + .number = GPBMessageOptions_FieldNumber_NoStandardDescriptorAccessor, + .hasIndex = 1, + .flags = GPBFieldOptional | GPBFieldHasDefaultValue, + .type = GPBTypeBool, + .offset = offsetof(GPBMessageOptions_Storage, noStandardDescriptorAccessor), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "deprecated", + .number = GPBMessageOptions_FieldNumber_Deprecated, + .hasIndex = 2, + .flags = GPBFieldOptional | GPBFieldHasDefaultValue, + .type = GPBTypeBool, + .offset = offsetof(GPBMessageOptions_Storage, deprecated), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "mapEntry", + .number = GPBMessageOptions_FieldNumber_MapEntry, + .hasIndex = 3, + .flags = GPBFieldOptional, + .type = GPBTypeBool, + .offset = offsetof(GPBMessageOptions_Storage, mapEntry), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "uninterpretedOptionArray", + .number = GPBMessageOptions_FieldNumber_UninterpretedOptionArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeMessage, + .offset = offsetof(GPBMessageOptions_Storage, uninterpretedOptionArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption), + .fieldOptions = NULL, + }, + }; + static GPBExtensionRange ranges[] = { + { .start = 1000, .end = 536870912 }, + }; + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBMessageOptions class] + rootClass:[GPBDescriptorRoot class] + file:GPBDescriptorRoot_FileDescriptor() + fields:fields + fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:NULL + enumCount:0 + ranges:ranges + rangeCount:sizeof(ranges) / sizeof(GPBExtensionRange) + storageSize:sizeof(GPBMessageOptions_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + +#pragma mark - GPBFieldOptions + +@implementation GPBFieldOptions + +@dynamic hasCtype, ctype; +@dynamic hasPacked, packed; +@dynamic hasLazy, lazy; +@dynamic hasDeprecated, deprecated; +@dynamic hasWeak, weak; +@dynamic uninterpretedOptionArray; + +typedef struct GPBFieldOptions_Storage { + uint32_t _has_storage_[1]; + BOOL packed; + BOOL deprecated; + BOOL lazy; + BOOL weak; + GPBFieldOptions_CType ctype; + NSMutableArray *uninterpretedOptionArray; +} GPBFieldOptions_Storage; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "ctype", + .number = GPBFieldOptions_FieldNumber_Ctype, + .hasIndex = 0, + .flags = GPBFieldOptional | GPBFieldHasDefaultValue | GPBFieldHasEnumDescriptor, + .type = GPBTypeEnum, + .offset = offsetof(GPBFieldOptions_Storage, ctype), + .defaultValue.valueEnum = GPBFieldOptions_CType_String, + .typeSpecific.enumDescFunc = GPBFieldOptions_CType_EnumDescriptor, + .fieldOptions = NULL, + }, + { + .name = "packed", + .number = GPBFieldOptions_FieldNumber_Packed, + .hasIndex = 1, + .flags = GPBFieldOptional, + .type = GPBTypeBool, + .offset = offsetof(GPBFieldOptions_Storage, packed), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "deprecated", + .number = GPBFieldOptions_FieldNumber_Deprecated, + .hasIndex = 3, + .flags = GPBFieldOptional | GPBFieldHasDefaultValue, + .type = GPBTypeBool, + .offset = offsetof(GPBFieldOptions_Storage, deprecated), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "lazy", + .number = GPBFieldOptions_FieldNumber_Lazy, + .hasIndex = 2, + .flags = GPBFieldOptional | GPBFieldHasDefaultValue, + .type = GPBTypeBool, + .offset = offsetof(GPBFieldOptions_Storage, lazy), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "weak", + .number = GPBFieldOptions_FieldNumber_Weak, + .hasIndex = 4, + .flags = GPBFieldOptional | GPBFieldHasDefaultValue, + .type = GPBTypeBool, + .offset = offsetof(GPBFieldOptions_Storage, weak), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "uninterpretedOptionArray", + .number = GPBFieldOptions_FieldNumber_UninterpretedOptionArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeMessage, + .offset = offsetof(GPBFieldOptions_Storage, uninterpretedOptionArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption), + .fieldOptions = NULL, + }, + }; + static GPBMessageEnumDescription enums[] = { + { .enumDescriptorFunc = GPBFieldOptions_CType_EnumDescriptor }, + }; + static GPBExtensionRange ranges[] = { + { .start = 1000, .end = 536870912 }, + }; + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBFieldOptions class] + rootClass:[GPBDescriptorRoot class] + file:GPBDescriptorRoot_FileDescriptor() + fields:fields + fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:enums + enumCount:sizeof(enums) / sizeof(GPBMessageEnumDescription) + ranges:ranges + rangeCount:sizeof(ranges) / sizeof(GPBExtensionRange) + storageSize:sizeof(GPBFieldOptions_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + +#pragma mark - Enum GPBFieldOptions_CType + +GPBEnumDescriptor *GPBFieldOptions_CType_EnumDescriptor(void) { + static GPBEnumDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageEnumValueDescription values[] = { + { .name = "String", .number = GPBFieldOptions_CType_String }, + { .name = "Cord", .number = GPBFieldOptions_CType_Cord }, + { .name = "StringPiece", .number = GPBFieldOptions_CType_StringPiece }, + }; + descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBFieldOptions_CType) + values:values + valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription) + enumVerifier:GPBFieldOptions_CType_IsValidValue]; + } + return descriptor; +} + +BOOL GPBFieldOptions_CType_IsValidValue(int32_t value__) { + switch (value__) { + case GPBFieldOptions_CType_String: + case GPBFieldOptions_CType_Cord: + case GPBFieldOptions_CType_StringPiece: + return YES; + default: + return NO; + } +} + +#pragma mark - GPBEnumOptions + +@implementation GPBEnumOptions + +@dynamic hasAllowAlias, allowAlias; +@dynamic hasDeprecated, deprecated; +@dynamic uninterpretedOptionArray; + +typedef struct GPBEnumOptions_Storage { + uint32_t _has_storage_[1]; + BOOL allowAlias; + BOOL deprecated; + NSMutableArray *uninterpretedOptionArray; +} GPBEnumOptions_Storage; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "allowAlias", + .number = GPBEnumOptions_FieldNumber_AllowAlias, + .hasIndex = 0, + .flags = GPBFieldOptional, + .type = GPBTypeBool, + .offset = offsetof(GPBEnumOptions_Storage, allowAlias), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "deprecated", + .number = GPBEnumOptions_FieldNumber_Deprecated, + .hasIndex = 1, + .flags = GPBFieldOptional | GPBFieldHasDefaultValue, + .type = GPBTypeBool, + .offset = offsetof(GPBEnumOptions_Storage, deprecated), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "uninterpretedOptionArray", + .number = GPBEnumOptions_FieldNumber_UninterpretedOptionArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeMessage, + .offset = offsetof(GPBEnumOptions_Storage, uninterpretedOptionArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption), + .fieldOptions = NULL, + }, + }; + static GPBExtensionRange ranges[] = { + { .start = 1000, .end = 536870912 }, + }; + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBEnumOptions class] + rootClass:[GPBDescriptorRoot class] + file:GPBDescriptorRoot_FileDescriptor() + fields:fields + fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:NULL + enumCount:0 + ranges:ranges + rangeCount:sizeof(ranges) / sizeof(GPBExtensionRange) + storageSize:sizeof(GPBEnumOptions_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + +#pragma mark - GPBEnumValueOptions + +@implementation GPBEnumValueOptions + +@dynamic hasDeprecated, deprecated; +@dynamic uninterpretedOptionArray; + +typedef struct GPBEnumValueOptions_Storage { + uint32_t _has_storage_[1]; + BOOL deprecated; + NSMutableArray *uninterpretedOptionArray; +} GPBEnumValueOptions_Storage; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "deprecated", + .number = GPBEnumValueOptions_FieldNumber_Deprecated, + .hasIndex = 0, + .flags = GPBFieldOptional | GPBFieldHasDefaultValue, + .type = GPBTypeBool, + .offset = offsetof(GPBEnumValueOptions_Storage, deprecated), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "uninterpretedOptionArray", + .number = GPBEnumValueOptions_FieldNumber_UninterpretedOptionArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeMessage, + .offset = offsetof(GPBEnumValueOptions_Storage, uninterpretedOptionArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption), + .fieldOptions = NULL, + }, + }; + static GPBExtensionRange ranges[] = { + { .start = 1000, .end = 536870912 }, + }; + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBEnumValueOptions class] + rootClass:[GPBDescriptorRoot class] + file:GPBDescriptorRoot_FileDescriptor() + fields:fields + fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:NULL + enumCount:0 + ranges:ranges + rangeCount:sizeof(ranges) / sizeof(GPBExtensionRange) + storageSize:sizeof(GPBEnumValueOptions_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + +#pragma mark - GPBServiceOptions + +@implementation GPBServiceOptions + +@dynamic hasDeprecated, deprecated; +@dynamic uninterpretedOptionArray; + +typedef struct GPBServiceOptions_Storage { + uint32_t _has_storage_[1]; + BOOL deprecated; + NSMutableArray *uninterpretedOptionArray; +} GPBServiceOptions_Storage; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "deprecated", + .number = GPBServiceOptions_FieldNumber_Deprecated, + .hasIndex = 0, + .flags = GPBFieldOptional | GPBFieldHasDefaultValue, + .type = GPBTypeBool, + .offset = offsetof(GPBServiceOptions_Storage, deprecated), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "uninterpretedOptionArray", + .number = GPBServiceOptions_FieldNumber_UninterpretedOptionArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeMessage, + .offset = offsetof(GPBServiceOptions_Storage, uninterpretedOptionArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption), + .fieldOptions = NULL, + }, + }; + static GPBExtensionRange ranges[] = { + { .start = 1000, .end = 536870912 }, + }; + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBServiceOptions class] + rootClass:[GPBDescriptorRoot class] + file:GPBDescriptorRoot_FileDescriptor() + fields:fields + fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:NULL + enumCount:0 + ranges:ranges + rangeCount:sizeof(ranges) / sizeof(GPBExtensionRange) + storageSize:sizeof(GPBServiceOptions_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + +#pragma mark - GPBMethodOptions + +@implementation GPBMethodOptions + +@dynamic hasDeprecated, deprecated; +@dynamic uninterpretedOptionArray; + +typedef struct GPBMethodOptions_Storage { + uint32_t _has_storage_[1]; + BOOL deprecated; + NSMutableArray *uninterpretedOptionArray; +} GPBMethodOptions_Storage; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "deprecated", + .number = GPBMethodOptions_FieldNumber_Deprecated, + .hasIndex = 0, + .flags = GPBFieldOptional | GPBFieldHasDefaultValue, + .type = GPBTypeBool, + .offset = offsetof(GPBMethodOptions_Storage, deprecated), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "uninterpretedOptionArray", + .number = GPBMethodOptions_FieldNumber_UninterpretedOptionArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeMessage, + .offset = offsetof(GPBMethodOptions_Storage, uninterpretedOptionArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption), + .fieldOptions = NULL, + }, + }; + static GPBExtensionRange ranges[] = { + { .start = 1000, .end = 536870912 }, + }; + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBMethodOptions class] + rootClass:[GPBDescriptorRoot class] + file:GPBDescriptorRoot_FileDescriptor() + fields:fields + fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:NULL + enumCount:0 + ranges:ranges + rangeCount:sizeof(ranges) / sizeof(GPBExtensionRange) + storageSize:sizeof(GPBMethodOptions_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + +#pragma mark - GPBUninterpretedOption + +@implementation GPBUninterpretedOption + +@dynamic nameArray; +@dynamic hasIdentifierValue, identifierValue; +@dynamic hasPositiveIntValue, positiveIntValue; +@dynamic hasNegativeIntValue, negativeIntValue; +@dynamic hasDoubleValue, doubleValue; +@dynamic hasStringValue, stringValue; +@dynamic hasAggregateValue, aggregateValue; + +typedef struct GPBUninterpretedOption_Storage { + uint32_t _has_storage_[1]; + NSMutableArray *nameArray; + NSString *identifierValue; + NSData *stringValue; + NSString *aggregateValue; + uint64_t positiveIntValue; + int64_t negativeIntValue; + double doubleValue; +} GPBUninterpretedOption_Storage; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "nameArray", + .number = GPBUninterpretedOption_FieldNumber_NameArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeMessage, + .offset = offsetof(GPBUninterpretedOption_Storage, nameArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption_NamePart), + .fieldOptions = NULL, + }, + { + .name = "identifierValue", + .number = GPBUninterpretedOption_FieldNumber_IdentifierValue, + .hasIndex = 1, + .flags = GPBFieldOptional, + .type = GPBTypeString, + .offset = offsetof(GPBUninterpretedOption_Storage, identifierValue), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "positiveIntValue", + .number = GPBUninterpretedOption_FieldNumber_PositiveIntValue, + .hasIndex = 2, + .flags = GPBFieldOptional, + .type = GPBTypeUInt64, + .offset = offsetof(GPBUninterpretedOption_Storage, positiveIntValue), + .defaultValue.valueUInt64 = 0ULL, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "negativeIntValue", + .number = GPBUninterpretedOption_FieldNumber_NegativeIntValue, + .hasIndex = 3, + .flags = GPBFieldOptional, + .type = GPBTypeInt64, + .offset = offsetof(GPBUninterpretedOption_Storage, negativeIntValue), + .defaultValue.valueInt64 = 0LL, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "doubleValue", + .number = GPBUninterpretedOption_FieldNumber_DoubleValue, + .hasIndex = 4, + .flags = GPBFieldOptional, + .type = GPBTypeDouble, + .offset = offsetof(GPBUninterpretedOption_Storage, doubleValue), + .defaultValue.valueDouble = 0, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "stringValue", + .number = GPBUninterpretedOption_FieldNumber_StringValue, + .hasIndex = 5, + .flags = GPBFieldOptional, + .type = GPBTypeData, + .offset = offsetof(GPBUninterpretedOption_Storage, stringValue), + .defaultValue.valueData = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "aggregateValue", + .number = GPBUninterpretedOption_FieldNumber_AggregateValue, + .hasIndex = 6, + .flags = GPBFieldOptional, + .type = GPBTypeString, + .offset = offsetof(GPBUninterpretedOption_Storage, aggregateValue), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + }; + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBUninterpretedOption class] + rootClass:[GPBDescriptorRoot class] + file:GPBDescriptorRoot_FileDescriptor() + fields:fields + fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:NULL + enumCount:0 + ranges:NULL + rangeCount:0 + storageSize:sizeof(GPBUninterpretedOption_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + +#pragma mark - GPBUninterpretedOption_NamePart + +@implementation GPBUninterpretedOption_NamePart + +@dynamic hasNamePart, namePart; +@dynamic hasIsExtension, isExtension; + +typedef struct GPBUninterpretedOption_NamePart_Storage { + uint32_t _has_storage_[1]; + BOOL isExtension; + NSString *namePart; +} GPBUninterpretedOption_NamePart_Storage; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "namePart", + .number = GPBUninterpretedOption_NamePart_FieldNumber_NamePart, + .hasIndex = 0, + .flags = GPBFieldRequired, + .type = GPBTypeString, + .offset = offsetof(GPBUninterpretedOption_NamePart_Storage, namePart), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "isExtension", + .number = GPBUninterpretedOption_NamePart_FieldNumber_IsExtension, + .hasIndex = 1, + .flags = GPBFieldRequired, + .type = GPBTypeBool, + .offset = offsetof(GPBUninterpretedOption_NamePart_Storage, isExtension), + .defaultValue.valueBool = NO, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + }; + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBUninterpretedOption_NamePart class] + rootClass:[GPBDescriptorRoot class] + file:GPBDescriptorRoot_FileDescriptor() + fields:fields + fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:NULL + enumCount:0 + ranges:NULL + rangeCount:0 + storageSize:sizeof(GPBUninterpretedOption_NamePart_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + +#pragma mark - GPBSourceCodeInfo + +@implementation GPBSourceCodeInfo + +@dynamic locationArray; + +typedef struct GPBSourceCodeInfo_Storage { + uint32_t _has_storage_[1]; + NSMutableArray *locationArray; +} GPBSourceCodeInfo_Storage; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "locationArray", + .number = GPBSourceCodeInfo_FieldNumber_LocationArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeMessage, + .offset = offsetof(GPBSourceCodeInfo_Storage, locationArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = GPBStringifySymbol(GPBSourceCodeInfo_Location), + .fieldOptions = NULL, + }, + }; + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBSourceCodeInfo class] + rootClass:[GPBDescriptorRoot class] + file:GPBDescriptorRoot_FileDescriptor() + fields:fields + fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:NULL + enumCount:0 + ranges:NULL + rangeCount:0 + storageSize:sizeof(GPBSourceCodeInfo_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + +#pragma mark - GPBSourceCodeInfo_Location + +@implementation GPBSourceCodeInfo_Location + +@dynamic pathArray; +@dynamic spanArray; +@dynamic hasLeadingComments, leadingComments; +@dynamic hasTrailingComments, trailingComments; +@dynamic leadingDetachedCommentsArray; + +typedef struct GPBSourceCodeInfo_Location_Storage { + uint32_t _has_storage_[1]; + GPBInt32Array *pathArray; + GPBInt32Array *spanArray; + NSString *leadingComments; + NSString *trailingComments; + NSMutableArray *leadingDetachedCommentsArray; +} GPBSourceCodeInfo_Location_Storage; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "pathArray", + .number = GPBSourceCodeInfo_Location_FieldNumber_PathArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated | GPBFieldPacked, + .type = GPBTypeInt32, + .offset = offsetof(GPBSourceCodeInfo_Location_Storage, pathArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = NULL, + #if GPBOBJC_INCLUDE_FIELD_OPTIONS + .fieldOptions = "\000\000\000\002\020\001", + #else + .fieldOptions = NULL, + #endif // GPBOBJC_INCLUDE_FIELD_OPTIONS + }, + { + .name = "spanArray", + .number = GPBSourceCodeInfo_Location_FieldNumber_SpanArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated | GPBFieldPacked, + .type = GPBTypeInt32, + .offset = offsetof(GPBSourceCodeInfo_Location_Storage, spanArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = NULL, + #if GPBOBJC_INCLUDE_FIELD_OPTIONS + .fieldOptions = "\000\000\000\002\020\001", + #else + .fieldOptions = NULL, + #endif // GPBOBJC_INCLUDE_FIELD_OPTIONS + }, + { + .name = "leadingComments", + .number = GPBSourceCodeInfo_Location_FieldNumber_LeadingComments, + .hasIndex = 2, + .flags = GPBFieldOptional, + .type = GPBTypeString, + .offset = offsetof(GPBSourceCodeInfo_Location_Storage, leadingComments), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "trailingComments", + .number = GPBSourceCodeInfo_Location_FieldNumber_TrailingComments, + .hasIndex = 3, + .flags = GPBFieldOptional, + .type = GPBTypeString, + .offset = offsetof(GPBSourceCodeInfo_Location_Storage, trailingComments), + .defaultValue.valueString = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "leadingDetachedCommentsArray", + .number = GPBSourceCodeInfo_Location_FieldNumber_LeadingDetachedCommentsArray, + .hasIndex = GPBNoHasBit, + .flags = GPBFieldRepeated, + .type = GPBTypeString, + .offset = offsetof(GPBSourceCodeInfo_Location_Storage, leadingDetachedCommentsArray), + .defaultValue.valueMessage = nil, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + }; + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBSourceCodeInfo_Location class] + rootClass:[GPBDescriptorRoot class] + file:GPBDescriptorRoot_FileDescriptor() + fields:fields + fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:NULL + enumCount:0 + ranges:NULL + rangeCount:0 + storageSize:sizeof(GPBSourceCodeInfo_Location_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + diff --git a/objectivec/google/protobuf/Duration.pbobjc.h b/objectivec/google/protobuf/Duration.pbobjc.h new file mode 100644 index 00000000..c452d0bb --- /dev/null +++ b/objectivec/google/protobuf/Duration.pbobjc.h @@ -0,0 +1,83 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/duration.proto + +#import "GPBProtocolBuffers.h" + +#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000 +#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources. +#endif + +CF_EXTERN_C_BEGIN + +@class GPBDuration; + + +#pragma mark - GPBDurationRoot + +@interface GPBDurationRoot : GPBRootObject +@end + +#pragma mark - GPBDuration + +typedef GPB_ENUM(GPBDuration_FieldNumber) { + GPBDuration_FieldNumber_Seconds = 1, + GPBDuration_FieldNumber_Nanos = 2, +}; + +// A Duration represents a signed, fixed-length span of time represented +// as a count of seconds and fractions of seconds at nanosecond +// resolution. It is independent of any calendar and concepts like "day" +// or "month". It is related to Timestamp in that the difference between +// two Timestamp values is a Duration and it can be added or subtracted +// from a Timestamp. Range is approximately +-10,000 years. +// +// Example 1: Compute Duration from two Timestamps in pseudo code. +// +// Timestamp start = ...; +// Timestamp end = ...; +// Duration duration = ...; +// +// duration.seconds = end.seconds - start.seconds; +// duration.nanos = end.nanos - start.nanos; +// +// if (duration.seconds < 0 && duration.nanos > 0) { +// duration.seconds += 1; +// duration.nanos -= 1000000000; +// } else if (durations.seconds > 0 && duration.nanos < 0) { +// duration.seconds -= 1; +// duration.nanos += 1000000000; +// } +// +// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. +// +// Timestamp start = ...; +// Duration duration = ...; +// Timestamp end = ...; +// +// end.seconds = start.seconds + duration.seconds; +// end.nanos = start.nanos + duration.nanos; +// +// if (end.nanos < 0) { +// end.seconds -= 1; +// end.nanos += 1000000000; +// } else if (end.nanos >= 1000000000) { +// end.seconds += 1; +// end.nanos -= 1000000000; +// } +@interface GPBDuration : GPBMessage + +// Signed seconds of the span of time. Must be from -315,576,000,000 +// to +315,576,000,000 inclusive. +@property(nonatomic, readwrite) int64_t seconds; + +// Signed fractions of a second at nanosecond resolution of the span +// of time. Durations less than one second are represented with a 0 +// `seconds` field and a positive or negative `nanos` field. For durations +// of one second or more, a non-zero value for the `nanos` field must be +// of the same sign as the `seconds` field. Must be from -999,999,999 +// to +999,999,999 inclusive. +@property(nonatomic, readwrite) int32_t nanos; + +@end + +CF_EXTERN_C_END diff --git a/objectivec/google/protobuf/Duration.pbobjc.m b/objectivec/google/protobuf/Duration.pbobjc.m new file mode 100644 index 00000000..cf0a3064 --- /dev/null +++ b/objectivec/google/protobuf/Duration.pbobjc.m @@ -0,0 +1,85 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/duration.proto + +#import "GPBProtocolBuffers_RuntimeSupport.h" + +#import "google/protobuf/Duration.pbobjc.h" + +#pragma mark - GPBDurationRoot + +@implementation GPBDurationRoot + +@end + +static GPBFileDescriptor *GPBDurationRoot_FileDescriptor(void) { + // This is called by +initialize so there is no need to worry + // about thread safety of the singleton. + static GPBFileDescriptor *descriptor = NULL; + if (!descriptor) { + descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" + syntax:GPBFileSyntaxProto3]; + } + return descriptor; +} + +#pragma mark - GPBDuration + +@implementation GPBDuration + +@dynamic seconds; +@dynamic nanos; + +typedef struct GPBDuration_Storage { + uint32_t _has_storage_[1]; + int32_t nanos; + int64_t seconds; +} GPBDuration_Storage; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "seconds", + .number = GPBDuration_FieldNumber_Seconds, + .hasIndex = 0, + .flags = GPBFieldOptional, + .type = GPBTypeInt64, + .offset = offsetof(GPBDuration_Storage, seconds), + .defaultValue.valueInt64 = 0LL, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "nanos", + .number = GPBDuration_FieldNumber_Nanos, + .hasIndex = 1, + .flags = GPBFieldOptional, + .type = GPBTypeInt32, + .offset = offsetof(GPBDuration_Storage, nanos), + .defaultValue.valueInt32 = 0, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + }; + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBDuration class] + rootClass:[GPBDurationRoot class] + file:GPBDurationRoot_FileDescriptor() + fields:fields + fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:NULL + enumCount:0 + ranges:NULL + rangeCount:0 + storageSize:sizeof(GPBDuration_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + diff --git a/objectivec/google/protobuf/Timestamp.pbobjc.h b/objectivec/google/protobuf/Timestamp.pbobjc.h new file mode 100644 index 00000000..c9fc9175 --- /dev/null +++ b/objectivec/google/protobuf/Timestamp.pbobjc.h @@ -0,0 +1,94 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/timestamp.proto + +#import "GPBProtocolBuffers.h" + +#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000 +#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources. +#endif + +CF_EXTERN_C_BEGIN + +@class GPBTimestamp; + + +#pragma mark - GPBTimestampRoot + +@interface GPBTimestampRoot : GPBRootObject +@end + +#pragma mark - GPBTimestamp + +typedef GPB_ENUM(GPBTimestamp_FieldNumber) { + GPBTimestamp_FieldNumber_Seconds = 1, + GPBTimestamp_FieldNumber_Nanos = 2, +}; + +// A Timestamp represents a point in time independent of any time zone +// or calendar, represented as seconds and fractions of seconds at +// nanosecond resolution in UTC Epoch time. It is encoded using the +// Proleptic Gregorian Calendar which extends the Gregorian calendar +// backwards to year one. It is encoded assuming all minutes are 60 +// seconds long, i.e. leap seconds are "smeared" so that no leap second +// table is needed for interpretation. Range is from +// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. +// By restricting to that range, we ensure that we can convert to +// and from RFC 3339 date strings. +// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt). +// +// Example 1: Compute Timestamp from POSIX `time()`. +// +// Timestamp timestamp; +// timestamp.set_seconds(time(NULL)); +// timestamp.set_nanos(0); +// +// Example 2: Compute Timestamp from POSIX `gettimeofday()`. +// +// struct timeval tv; +// gettimeofday(&tv, NULL); +// +// Timestamp timestamp; +// timestamp.set_seconds(tv.tv_sec); +// timestamp.set_nanos(tv.tv_usec * 1000); +// +// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. +// +// FILETIME ft; +// GetSystemTimeAsFileTime(&ft); +// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; +// +// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z +// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. +// Timestamp timestamp; +// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); +// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); +// +// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. +// +// long millis = System.currentTimeMillis(); +// +// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) +// .setNanos((int) ((millis % 1000) * 1000000)).build(); +// +// Example 5: Compute Timestamp from Python `datetime.datetime`. +// +// now = datetime.datetime.utcnow() +// seconds = int(time.mktime(now.timetuple())) +// nanos = now.microsecond * 1000 +// timestamp = Timestamp(seconds=seconds, nanos=nanos) +@interface GPBTimestamp : GPBMessage + +// Represents seconds of UTC time since Unix epoch +// 1970-01-01T00:00:00Z. Must be from from 0001-01-01T00:00:00Z to +// 9999-12-31T23:59:59Z inclusive. +@property(nonatomic, readwrite) int64_t seconds; + +// Non-negative fractions of a second at nanosecond resolution. Negative +// second values with fractions must still have non-negative nanos values +// that count forward in time. Must be from 0 to 999,999,999 +// inclusive. +@property(nonatomic, readwrite) int32_t nanos; + +@end + +CF_EXTERN_C_END diff --git a/objectivec/google/protobuf/Timestamp.pbobjc.m b/objectivec/google/protobuf/Timestamp.pbobjc.m new file mode 100644 index 00000000..1c8d3c76 --- /dev/null +++ b/objectivec/google/protobuf/Timestamp.pbobjc.m @@ -0,0 +1,85 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/timestamp.proto + +#import "GPBProtocolBuffers_RuntimeSupport.h" + +#import "google/protobuf/Timestamp.pbobjc.h" + +#pragma mark - GPBTimestampRoot + +@implementation GPBTimestampRoot + +@end + +static GPBFileDescriptor *GPBTimestampRoot_FileDescriptor(void) { + // This is called by +initialize so there is no need to worry + // about thread safety of the singleton. + static GPBFileDescriptor *descriptor = NULL; + if (!descriptor) { + descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" + syntax:GPBFileSyntaxProto3]; + } + return descriptor; +} + +#pragma mark - GPBTimestamp + +@implementation GPBTimestamp + +@dynamic seconds; +@dynamic nanos; + +typedef struct GPBTimestamp_Storage { + uint32_t _has_storage_[1]; + int32_t nanos; + int64_t seconds; +} GPBTimestamp_Storage; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "seconds", + .number = GPBTimestamp_FieldNumber_Seconds, + .hasIndex = 0, + .flags = GPBFieldOptional, + .type = GPBTypeInt64, + .offset = offsetof(GPBTimestamp_Storage, seconds), + .defaultValue.valueInt64 = 0LL, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + { + .name = "nanos", + .number = GPBTimestamp_FieldNumber_Nanos, + .hasIndex = 1, + .flags = GPBFieldOptional, + .type = GPBTypeInt32, + .offset = offsetof(GPBTimestamp_Storage, nanos), + .defaultValue.valueInt32 = 0, + .typeSpecific.className = NULL, + .fieldOptions = NULL, + }, + }; + descriptor = [GPBDescriptor allocDescriptorForClass:[GPBTimestamp class] + rootClass:[GPBTimestampRoot class] + file:GPBTimestampRoot_FileDescriptor() + fields:fields + fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:NULL + enumCount:0 + ranges:NULL + rangeCount:0 + storageSize:sizeof(GPBTimestamp_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + diff --git a/protobuf-lite.pc.in b/protobuf-lite.pc.in index 29c218e5..80f1f461 100644 --- a/protobuf-lite.pc.in +++ b/protobuf-lite.pc.in @@ -8,6 +8,4 @@ Description: Google's Data Interchange Format Version: @VERSION@ Libs: -L${libdir} -lprotobuf-lite @PTHREAD_CFLAGS@ @PTHREAD_LIBS@ Cflags: -I${includedir} @PTHREAD_CFLAGS@ -# Commented out because it crashes pkg-config *sigh*: -# http://bugs.freedesktop.org/show_bug.cgi?id=13265 -# Conflicts: protobuf +Conflicts: protobuf diff --git a/protobuf.pc.in b/protobuf.pc.in index 29f24877..49014903 100644 --- a/protobuf.pc.in +++ b/protobuf.pc.in @@ -9,6 +9,4 @@ Version: @VERSION@ Libs: -L${libdir} -lprotobuf @PTHREAD_CFLAGS@ @PTHREAD_LIBS@ Libs.private: @LIBS@ Cflags: -I${includedir} @PTHREAD_CFLAGS@ -# Commented out because it crashes pkg-config *sigh*: -# http://bugs.freedesktop.org/show_bug.cgi?id=13265 -# Conflicts: protobuf-lite +Conflicts: protobuf-lite diff --git a/protoc-artifacts/Dockerfile b/protoc-artifacts/Dockerfile new file mode 100644 index 00000000..fd35b89f --- /dev/null +++ b/protoc-artifacts/Dockerfile @@ -0,0 +1,40 @@ +FROM centos:6.6 + +RUN yum install -y git \ + tar \ + wget \ + make \ + autoconf \ + curl-devel \ + unzip \ + automake \ + libtool \ + glibc-static.i686 \ + glibc-devel \ + glibc-devel.i686 + +# Install Java 8 +RUN wget -q --no-cookies --no-check-certificate \ + --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u45-b14/jdk-8u45-linux-x64.tar.gz" \ + -O - | tar xz -C /var/local +ENV JAVA_HOME /var/local/jdk1.8.0_45 +ENV PATH $JAVA_HOME/bin:$PATH + +# Install Maven +RUN wget -q http://apache.cs.utah.edu/maven/maven-3/3.3.3/binaries/apache-maven-3.3.3-bin.tar.gz -O - | \ + tar xz -C /var/local +ENV PATH /var/local/apache-maven-3.3.3/bin:$PATH + +# Install GCC 4.7 to support -static-libstdc++ +RUN wget http://people.centos.org/tru/devtools-1.1/devtools-1.1.repo -P /etc/yum.repos.d +RUN bash -c 'echo "enabled=1" >> /etc/yum.repos.d/devtools-1.1.repo' +RUN bash -c "sed -e 's/\$basearch/i386/g' /etc/yum.repos.d/devtools-1.1.repo > /etc/yum.repos.d/devtools-i386-1.1.repo" +RUN sed -e 's/testing-/testing-i386-/g' -i /etc/yum.repos.d/devtools-i386-1.1.repo +RUN yum install -y devtoolset-1.1 \ + devtoolset-1.1-libstdc++-devel \ + devtoolset-1.1-libstdc++-devel.i686 + +RUN git clone --depth 1 https://github.com/google/protobuf.git + +# Start in devtoolset environment that uses GCC 4.7 +CMD ["scl", "enable", "devtoolset-1.1", "bash"] diff --git a/protoc-artifacts/README.md b/protoc-artifacts/README.md index 3a530197..06091cfe 100644 --- a/protoc-artifacts/README.md +++ b/protoc-artifacts/README.md @@ -63,9 +63,6 @@ deployment for all platforms. Currently the following platforms are supported: - MSYS with MinGW32 (x86_32 only) - MacOSX (x86_32 and x86_64) -Remove any ``SNAPSHOT`` or ``pre`` suffix from the version string before -deploying. - Use the following command to deploy artifacts for the host platform to a staging repository. ``` @@ -90,6 +87,23 @@ When you have done deployment for all platforms, go to https://oss.sonatype.org/#stagingRepositories, verify that the staging repository has all the binaries, close and release this repository. +### Tips for deploying on Linux +We build on Centos 6.6 to provide a good compatibility for not very new +systems. We have provided a ``Dockerfile`` under this directory to build the +environment. It has been tested with Docker 1.6.1. + +To build a image: +``` +$ docker build -t protoc-artifacts . +``` + +To run the image: +``` +$ docker run -it --rm=true protoc-artifacts +``` + +The Protobuf repository has been cloned into ``/protobuf``. + ### Tips for deploying on Windows Under Windows the following error may occur: ``gpg: cannot open tty `no tty': No such file or directory``. This can be fixed by configuring gpg through an @@ -118,3 +132,12 @@ stored: </activeProfiles> </settings> ``` + +### Tested build environments +We have succesfully built artifacts on the following environments: +- Linux x86_32 and x86_64: + - Centos 6.6 (within Docker 1.6.1) + - Ubuntu 14.04.2 64-bit +- Windows x86_32: MSYS with ``mingw32-gcc-g++ 4.8.1-4`` on Windows 7 64-bit +- Windows x86_64: Cygwin64 with ``mingw64-x86_64-gcc-g++ 4.8.3-1`` on Windows 7 64-bit +- Mac OS X x86_32 and x86_64: Mac OS X 10.9.5 diff --git a/protoc-artifacts/build-protoc.sh b/protoc-artifacts/build-protoc.sh index 96ca97c2..2f67c508 100755 --- a/protoc-artifacts/build-protoc.sh +++ b/protoc-artifacts/build-protoc.sh @@ -158,6 +158,9 @@ if [[ "$(uname)" == CYGWIN* ]]; then elif [[ "$(uname)" == MINGW32* ]]; then assertEq "$OS" windows $LINENO assertEq "$ARCH" x86_32 $LINENO +elif [[ "$(uname)" == MINGW64* ]]; then + assertEq "$OS" windows $LINENO + assertEq "$ARCH" x86_64 $LINENO elif [[ "$(uname)" == Linux* ]]; then if [[ "$OS" == linux ]]; then if [[ "$ARCH" == x86_64 ]]; then @@ -209,7 +212,7 @@ export CXXFLAGS LDFLAGS TARGET_FILE=target/protoc.exe cd "$WORKING_DIR"/.. && ./configure $CONFIGURE_ARGS && - cd src && make clean && make $MAKE_TARGET && + cd src && make clean && make google/protobuf/stubs/pbconfig.h $MAKE_TARGET && cd "$WORKING_DIR" && mkdir -p target && (cp ../src/protoc $TARGET_FILE || cp ../src/protoc.exe $TARGET_FILE) || exit 1 diff --git a/python/MANIFEST.in b/python/MANIFEST.in new file mode 100644 index 00000000..26088826 --- /dev/null +++ b/python/MANIFEST.in @@ -0,0 +1,14 @@ +prune google/protobuf/internal/import_test_package +exclude google/protobuf/internal/*_pb2.py +exclude google/protobuf/internal/*_test.py +exclude google/protobuf/internal/*.proto +exclude google/protobuf/internal/test_util.py + +recursive-exclude google *_test.py +recursive-exclude google *_test.proto +recursive-exclude google unittest*_pb2.py + +global-exclude *.dll +global-exclude *.pyc +global-exclude *.pyo +global-exclude *.so diff --git a/python/google/protobuf/internal/_parameterized.py b/python/google/protobuf/internal/_parameterized.py index c44e77e4..400b2216 100755 --- a/python/google/protobuf/internal/_parameterized.py +++ b/python/google/protobuf/internal/_parameterized.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/env python # # Protocol Buffers - Google's data interchange format # Copyright 2008 Google Inc. All rights reserved. diff --git a/python/google/protobuf/internal/descriptor_database_test.py b/python/google/protobuf/internal/descriptor_database_test.py index edf66a63..56fe14e9 100644 --- a/python/google/protobuf/internal/descriptor_database_test.py +++ b/python/google/protobuf/internal/descriptor_database_test.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/env python # # Protocol Buffers - Google's data interchange format # Copyright 2008 Google Inc. All rights reserved. diff --git a/python/google/protobuf/internal/descriptor_pool_test.py b/python/google/protobuf/internal/descriptor_pool_test.py index 6d04ebaa..7d145f42 100644 --- a/python/google/protobuf/internal/descriptor_pool_test.py +++ b/python/google/protobuf/internal/descriptor_pool_test.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/env python # # Protocol Buffers - Google's data interchange format # Copyright 2008 Google Inc. All rights reserved. diff --git a/python/google/protobuf/internal/descriptor_test.py b/python/google/protobuf/internal/descriptor_test.py index 549af088..335caee6 100755 --- a/python/google/protobuf/internal/descriptor_test.py +++ b/python/google/protobuf/internal/descriptor_test.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/env python # # Protocol Buffers - Google's data interchange format # Copyright 2008 Google Inc. All rights reserved. diff --git a/python/google/protobuf/internal/generator_test.py b/python/google/protobuf/internal/generator_test.py index 50fc1922..ccc5860b 100755 --- a/python/google/protobuf/internal/generator_test.py +++ b/python/google/protobuf/internal/generator_test.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/env python # # Protocol Buffers - Google's data interchange format # Copyright 2008 Google Inc. All rights reserved. diff --git a/python/google/protobuf/internal/message_factory_test.py b/python/google/protobuf/internal/message_factory_test.py index 45ddcd26..626c3fc9 100644 --- a/python/google/protobuf/internal/message_factory_test.py +++ b/python/google/protobuf/internal/message_factory_test.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/env python # # Protocol Buffers - Google's data interchange format # Copyright 2008 Google Inc. All rights reserved. diff --git a/python/google/protobuf/internal/message_test.py b/python/google/protobuf/internal/message_test.py index ce79b607..4ecaa1c7 100755 --- a/python/google/protobuf/internal/message_test.py +++ b/python/google/protobuf/internal/message_test.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/env python # # Protocol Buffers - Google's data interchange format # Copyright 2008 Google Inc. All rights reserved. diff --git a/python/google/protobuf/internal/proto_builder_test.py b/python/google/protobuf/internal/proto_builder_test.py index 9229205a..b1e57f35 100644 --- a/python/google/protobuf/internal/proto_builder_test.py +++ b/python/google/protobuf/internal/proto_builder_test.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/env python # # Protocol Buffers - Google's data interchange format # Copyright 2008 Google Inc. All rights reserved. diff --git a/python/google/protobuf/internal/reflection_test.py b/python/google/protobuf/internal/reflection_test.py index 8f28f4d9..ae79c78b 100755 --- a/python/google/protobuf/internal/reflection_test.py +++ b/python/google/protobuf/internal/reflection_test.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/env python # -*- coding: utf-8 -*- # # Protocol Buffers - Google's data interchange format diff --git a/python/google/protobuf/internal/service_reflection_test.py b/python/google/protobuf/internal/service_reflection_test.py index e3f71545..de462124 100755 --- a/python/google/protobuf/internal/service_reflection_test.py +++ b/python/google/protobuf/internal/service_reflection_test.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/env python # # Protocol Buffers - Google's data interchange format # Copyright 2008 Google Inc. All rights reserved. @@ -81,7 +81,7 @@ class FooUnitTest(unittest.TestCase): self.assertEqual('Method Bar not implemented.', rpc_controller.failure_message) self.assertEqual(None, self.callback_response) - + class MyServiceImpl(unittest_pb2.TestService): def Foo(self, rpc_controller, request, done): self.foo_called = True diff --git a/python/google/protobuf/internal/symbol_database_test.py b/python/google/protobuf/internal/symbol_database_test.py index a58cb1a4..c888aff7 100644 --- a/python/google/protobuf/internal/symbol_database_test.py +++ b/python/google/protobuf/internal/symbol_database_test.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/env python # # Protocol Buffers - Google's data interchange format # Copyright 2008 Google Inc. All rights reserved. diff --git a/python/google/protobuf/internal/text_encoding_test.py b/python/google/protobuf/internal/text_encoding_test.py index 48c30f01..27896b94 100755 --- a/python/google/protobuf/internal/text_encoding_test.py +++ b/python/google/protobuf/internal/text_encoding_test.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/env python # # Protocol Buffers - Google's data interchange format # Copyright 2008 Google Inc. All rights reserved. diff --git a/python/google/protobuf/internal/text_format_test.py b/python/google/protobuf/internal/text_format_test.py index 0135099d..bf7e06ee 100755 --- a/python/google/protobuf/internal/text_format_test.py +++ b/python/google/protobuf/internal/text_format_test.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/env python # # Protocol Buffers - Google's data interchange format # Copyright 2008 Google Inc. All rights reserved. diff --git a/python/google/protobuf/internal/unknown_fields_test.py b/python/google/protobuf/internal/unknown_fields_test.py index d116920e..9337ae8a 100755 --- a/python/google/protobuf/internal/unknown_fields_test.py +++ b/python/google/protobuf/internal/unknown_fields_test.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/env python # -*- coding: utf-8 -*- # # Protocol Buffers - Google's data interchange format diff --git a/python/google/protobuf/internal/wire_format_test.py b/python/google/protobuf/internal/wire_format_test.py index e40a40cc..5cd7fcb9 100755 --- a/python/google/protobuf/internal/wire_format_test.py +++ b/python/google/protobuf/internal/wire_format_test.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/env python # # Protocol Buffers - Google's data interchange format # Copyright 2008 Google Inc. All rights reserved. diff --git a/python/setup.py b/python/setup.py index fa98cd31..1764ec87 100755 --- a/python/setup.py +++ b/python/setup.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/env python # # See README for usage instructions. import sys @@ -8,28 +8,29 @@ import subprocess # We must use setuptools, not distutils, because we need to use the # namespace_packages option for the "google" package. try: - from setuptools import setup, Extension + from setuptools import setup, Extension, find_packages except ImportError: try: from ez_setup import use_setuptools use_setuptools() - from setuptools import setup, Extension + from setuptools import setup, Extension, find_packages except ImportError: sys.stderr.write( "Could not import setuptools; make sure you have setuptools or " - "ez_setup installed.\n") + "ez_setup installed.\n" + ) raise + from distutils.command.clean import clean as _clean -if sys.version_info[0] >= 3: - # Python 3 - from distutils.command.build_py import build_py_2to3 as _build_py + +if sys.version_info[0] == 3: + # Python 3 + from distutils.command.build_py import build_py_2to3 as _build_py else: - # Python 2 - from distutils.command.build_py import build_py as _build_py + # Python 2 + from distutils.command.build_py import build_py as _build_py from distutils.spawn import find_executable -maintainer_email = "protobuf@googlegroups.com" - # Find the Protocol Compiler. if 'PROTOC' in os.environ and os.path.exists(os.environ['PROTOC']): protoc = os.environ['PROTOC'] @@ -44,15 +45,15 @@ elif os.path.exists("../vsprojects/Release/protoc.exe"): else: protoc = find_executable("protoc") + def GetVersion(): """Gets the version from google/protobuf/__init__.py - Do not import google.protobuf.__init__ directly, because an installed protobuf - library may be loaded instead. + Do not import google.protobuf.__init__ directly, because an installed + protobuf library may be loaded instead.""" - """ with open(os.path.join('google', 'protobuf', '__init__.py')) as version_file: - exec(version_file.read()) + exec(version_file.read(), globals()) return __version__ @@ -66,22 +67,24 @@ def generate_proto(source): if (not os.path.exists(output) or (os.path.exists(source) and os.path.getmtime(source) > os.path.getmtime(output))): - print ("Generating %s..." % output) + print("Generating %s..." % output) if not os.path.exists(source): sys.stderr.write("Can't find required file: %s\n" % source) sys.exit(-1) - if protoc == None: + if protoc is None: sys.stderr.write( - "protoc is not installed nor found in ../src. Please compile it " - "or install the binary package.\n") + "protoc is not installed nor found in ../src. " + "Please compile it or install the binary package.\n" + ) sys.exit(-1) - protoc_command = [ protoc, "-I../src", "-I.", "--python_out=.", source ] + protoc_command = [protoc, "-I../src", "-I.", "--python_out=.", source] if subprocess.call(protoc_command) != 0: sys.exit(-1) + def GenerateUnittestProtos(): generate_proto("../src/google/protobuf/unittest.proto") generate_proto("../src/google/protobuf/unittest_custom_options.proto") @@ -92,17 +95,18 @@ def GenerateUnittestProtos(): generate_proto("../src/google/protobuf/unittest_proto3_arena.proto") generate_proto("google/protobuf/internal/descriptor_pool_test1.proto") generate_proto("google/protobuf/internal/descriptor_pool_test2.proto") - generate_proto("google/protobuf/internal/test_bad_identifiers.proto") - generate_proto("google/protobuf/internal/missing_enum_values.proto") - generate_proto("google/protobuf/internal/more_extensions.proto") - generate_proto("google/protobuf/internal/more_extensions_dynamic.proto") - generate_proto("google/protobuf/internal/more_messages.proto") generate_proto("google/protobuf/internal/factory_test1.proto") generate_proto("google/protobuf/internal/factory_test2.proto") generate_proto("google/protobuf/internal/import_test_package/inner.proto") generate_proto("google/protobuf/internal/import_test_package/outer.proto") + generate_proto("google/protobuf/internal/missing_enum_values.proto") + generate_proto("google/protobuf/internal/more_extensions.proto") + generate_proto("google/protobuf/internal/more_extensions_dynamic.proto") + generate_proto("google/protobuf/internal/more_messages.proto") + generate_proto("google/protobuf/internal/test_bad_identifiers.proto") generate_proto("google/protobuf/pyext/python.proto") + class clean(_clean): def run(self): # Delete generated files in the code tree. @@ -110,12 +114,13 @@ class clean(_clean): for filename in filenames: filepath = os.path.join(dirpath, filename) if filepath.endswith("_pb2.py") or filepath.endswith(".pyc") or \ - filepath.endswith(".so") or filepath.endswith(".o") or \ - filepath.endswith('google/protobuf/compiler/__init__.py'): + filepath.endswith(".so") or filepath.endswith(".o") or \ + filepath.endswith('google/protobuf/compiler/__init__.py'): os.remove(filepath) # _clean is an old-style class, so super() doesn't work. _clean.run(self) + class build_py(_build_py): def run(self): # Generate necessary .proto file if it doesn't exist. @@ -132,11 +137,11 @@ class build_py(_build_py): # _build_py is an old-style class, so super() doesn't work. _build_py.run(self) # TODO(mrovner): Subclass to run 2to3 on some files only. - # Tracing what https://wiki.python.org/moin/PortingPythonToPy3k's "Approach 2" - # section on how to get 2to3 to run on source files during install under - # Python 3. This class seems like a good place to put logic that calls - # python3's distutils.util.run_2to3 on the subset of the files we have in our - # release that are subject to conversion. + # Tracing what https://wiki.python.org/moin/PortingPythonToPy3k's + # "Approach 2" section on how to get 2to3 to run on source files during + # install under Python 3. This class seems like a good place to put logic + # that calls python3's distutils.util.run_2to3 on the subset of the files we + # have in our release that are subject to conversion. # See code reference in previous code review. if __name__ == '__main__': @@ -145,61 +150,49 @@ if __name__ == '__main__': if cpp_impl in sys.argv: sys.argv.remove(cpp_impl) # C++ implementation extension - ext_module_list.append(Extension( - "google.protobuf.pyext._message", - [ "google/protobuf/pyext/descriptor.cc", - "google/protobuf/pyext/descriptor_containers.cc", - "google/protobuf/pyext/descriptor_pool.cc", - "google/protobuf/pyext/message.cc", - "google/protobuf/pyext/extension_dict.cc", - "google/protobuf/pyext/repeated_scalar_container.cc", - "google/protobuf/pyext/repeated_composite_container.cc" ], - define_macros=[('GOOGLE_PROTOBUF_HAS_ONEOF', '1')], - include_dirs = [ ".", "../src" ], - libraries = [ "protobuf" ], - library_dirs = [ '../src/.libs' ], - )) + ext_module_list.append( + Extension( + "google.protobuf.pyext._message", + [ + "google/protobuf/pyext/descriptor.cc", + "google/protobuf/pyext/descriptor_containers.cc", + "google/protobuf/pyext/descriptor_pool.cc", + "google/protobuf/pyext/extension_dict.cc", + "google/protobuf/pyext/message.cc", + "google/protobuf/pyext/repeated_composite_container.cc", + "google/protobuf/pyext/repeated_scalar_container.cc", + ], + define_macros=[('GOOGLE_PROTOBUF_HAS_ONEOF', '1')], + include_dirs=[".", "../src"], + libraries=['protobuf'], + library_dirs=['../src/.libs'], + ) + ) os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION'] = 'cpp' - setup(name = 'protobuf', - version = GetVersion(), - packages = [ 'google' ], - namespace_packages = [ 'google' ], - test_suite = 'google.protobuf.internal', - # Must list modules explicitly so that we don't install tests. - py_modules = [ - 'google.protobuf.internal.api_implementation', - 'google.protobuf.internal.containers', - 'google.protobuf.internal.decoder', - 'google.protobuf.internal.encoder', - 'google.protobuf.internal.enum_type_wrapper', - 'google.protobuf.internal.message_listener', - 'google.protobuf.internal.python_message', - 'google.protobuf.internal.type_checkers', - 'google.protobuf.internal.wire_format', - 'google.protobuf.descriptor', - 'google.protobuf.descriptor_pb2', - 'google.protobuf.compiler.plugin_pb2', - 'google.protobuf.message', - 'google.protobuf.descriptor_database', - 'google.protobuf.descriptor_pool', - 'google.protobuf.message_factory', - 'google.protobuf.proto_builder', - 'google.protobuf.pyext.cpp_message', - 'google.protobuf.reflection', - 'google.protobuf.service', - 'google.protobuf.service_reflection', - 'google.protobuf.symbol_database', - 'google.protobuf.text_encoding', - 'google.protobuf.text_format'], - cmdclass = { 'clean': clean, 'build_py': build_py }, - install_requires = ['setuptools'], - ext_modules = ext_module_list, - url = 'https://developers.google.com/protocol-buffers/', - maintainer = maintainer_email, - maintainer_email = 'protobuf@googlegroups.com', - license = 'New BSD License', - description = 'Protocol Buffers', - long_description = - "Protocol Buffers are Google's data interchange format.", - ) + setup( + name='protobuf', + version=GetVersion(), + description='Protocol Buffers', + long_description="Protocol Buffers are Google's data interchange format", + url='https://developers.google.com/protocol-buffers/', + maintainer='protobuf@googlegroups.com', + maintainer_email='protobuf@googlegroups.com', + license='New BSD License', + classifiers=[ + 'Programming Language :: Python :: 2.7', + ], + namespace_packages=['google'], + packages=find_packages( + exclude=[ + 'import_test_package', + ], + ), + test_suite='google.protobuf.internal', + cmdclass={ + 'clean': clean, + 'build_py': build_py, + }, + install_requires=['setuptools'], + ext_modules=ext_module_list, + ) diff --git a/ruby/.gitignore b/ruby/.gitignore index 80c978f2..bd8745dd 100644 --- a/ruby/.gitignore +++ b/ruby/.gitignore @@ -4,3 +4,5 @@ tags lib/google/protobuf_java.jar protobuf-jruby.iml target/ +pkg/ +tmp/ diff --git a/ruby/Gemfile.lock b/ruby/Gemfile.lock index 89deb47d..6f349276 100644 --- a/ruby/Gemfile.lock +++ b/ruby/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - google-protobuf (3.0.0.alpha.2) + google-protobuf (3.0.0.alpha.3.1.pre) GEM remote: https://rubygems.org/ diff --git a/ruby/README.md b/ruby/README.md index d2fa76ab..16474322 100644 --- a/ruby/README.md +++ b/ruby/README.md @@ -63,7 +63,7 @@ To build this Ruby extension, you will need: To Build the JRuby extension, you will need: * Maven -* The latest version of the protobuf java library +* The latest version of the protobuf java library (see ../java/README.md) * Install JRuby via rbenv or RVM First switch to the desired platform with rbenv or RVM. @@ -75,8 +75,9 @@ Then install the required Ruby gems: Then build the Gem: - $ rake gem - $ gem install pkg/protobuf-$VERSION.gem + $ rake + $ rake clobber_package gem + $ gem install `ls pkg/google-protobuf-*.gem` To run the specs: diff --git a/ruby/Rakefile b/ruby/Rakefile index 7c1d8495..c25103d8 100644 --- a/ruby/Rakefile +++ b/ruby/Rakefile @@ -6,6 +6,9 @@ require "rake/testtask" spec = Gem::Specification.load("google-protobuf.gemspec") if RUBY_PLATFORM == "java" + if `which mvn` == '' + raise ArgumentError, "maven needs to be installed" + end task :clean do system("mvn clean") end diff --git a/ruby/ext/google/protobuf_c/repeated_field.c b/ruby/ext/google/protobuf_c/repeated_field.c index 8cf2e29b..5148ee87 100644 --- a/ruby/ext/google/protobuf_c/repeated_field.c +++ b/ruby/ext/google/protobuf_c/repeated_field.c @@ -47,6 +47,15 @@ RepeatedField* ruby_to_RepeatedField(VALUE _self) { return self; } +static int index_position(VALUE _index, RepeatedField* repeated_field) { + int index = NUM2INT(_index); + if (index < 0 && repeated_field->size > 0) { + index = repeated_field->size + index; + } + return index; +} + + /* * call-seq: * RepeatedField.each(&block) @@ -74,8 +83,7 @@ VALUE RepeatedField_each(VALUE _self) { * call-seq: * RepeatedField.[](index) => value * - * Accesses the element at the given index. Throws an exception on out-of-bounds - * errors. + * Accesses the element at the given index. Returns nil on out-of-bounds */ VALUE RepeatedField_index(VALUE _self, VALUE _index) { RepeatedField* self = ruby_to_RepeatedField(_self); @@ -83,9 +91,9 @@ VALUE RepeatedField_index(VALUE _self, VALUE _index) { upb_fieldtype_t field_type = self->field_type; VALUE field_type_class = self->field_type_class; - int index = NUM2INT(_index); + int index = index_position(_index, self); if (index < 0 || index >= self->size) { - rb_raise(rb_eRangeError, "Index out of range"); + return Qnil; } void* memory = (void *) (((uint8_t *)self->elements) + index * element_size); @@ -105,9 +113,9 @@ VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val) { VALUE field_type_class = self->field_type_class; int element_size = native_slot_size(field_type); - int index = NUM2INT(_index); + int index = index_position(_index, self); if (index < 0 || index >= (INT_MAX - 1)) { - rb_raise(rb_eRangeError, "Index out of range"); + return Qnil; } if (index >= self->size) { RepeatedField_reserve(self, index + 1); diff --git a/ruby/ext/google/protobuf_c/storage.c b/ruby/ext/google/protobuf_c/storage.c index 5b1549d2..2ad8bd74 100644 --- a/ruby/ext/google/protobuf_c/storage.c +++ b/ruby/ext/google/protobuf_c/storage.c @@ -155,7 +155,9 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class, break; } case UPB_TYPE_MESSAGE: { - if (CLASS_OF(value) != type_class) { + if (CLASS_OF(value) == CLASS_OF(Qnil)) { + value = Qnil; + } else if (CLASS_OF(value) != type_class) { rb_raise(rb_eTypeError, "Invalid type %s to assign to submessage field.", rb_class2name(CLASS_OF(value))); diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec index abbbde35..28cdebf5 100644 --- a/ruby/google-protobuf.gemspec +++ b/ruby/google-protobuf.gemspec @@ -4,10 +4,11 @@ Gem::Specification.new do |s| s.licenses = ["BSD"] s.summary = "Protocol Buffers" s.description = "Protocol Buffers are Google's data interchange format." + s.homepage = "https://developers.google.com/protocol-buffers" s.authors = ["Protobuf Authors"] s.email = "protobuf@googlegroups.com" s.require_paths = ["lib"] - s.files = ["lib/google/protobuf.rb"] + s.files = `git ls-files -z`.split("\x0").find_all{|f| f =~ /lib\/.+\.rb/} unless RUBY_PLATFORM == "java" s.files += `git ls-files "*.c" "*.h" extconf.rb Makefile`.split s.extensions= ["ext/google/protobuf_c/extconf.rb"] diff --git a/ruby/lib/google/protobuf.rb b/ruby/lib/google/protobuf.rb index 75869dd8..72797245 100644 --- a/ruby/lib/google/protobuf.rb +++ b/ruby/lib/google/protobuf.rb @@ -34,3 +34,5 @@ if RUBY_PLATFORM == "java" else require 'google/protobuf_c' end + +require 'google/protobuf/repeated_field' diff --git a/ruby/lib/google/protobuf/repeated_field.rb b/ruby/lib/google/protobuf/repeated_field.rb new file mode 100644 index 00000000..5b934e56 --- /dev/null +++ b/ruby/lib/google/protobuf/repeated_field.rb @@ -0,0 +1,40 @@ +# 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. + +# add syntatic sugar on top of the core library +module Google + module Protobuf + class RepeatedField + + alias_method :size, :length + + end + end +end diff --git a/ruby/pom.xml b/ruby/pom.xml index 1630fe84..01f0e16b 100644 --- a/ruby/pom.xml +++ b/ruby/pom.xml @@ -78,7 +78,7 @@ <dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> - <version>3.0.0-pre</version> + <version>3.0.0-alpha-3-pre</version> </dependency> </dependencies> </project> diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java index 04bc0b76..c7fd7aa7 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java @@ -246,16 +246,15 @@ public class RubyMessage extends RubyObject { public IRubyObject dup(ThreadContext context) { RubyMessage dup = (RubyMessage) metaClass.newInstance(context, Block.NULL_BLOCK); IRubyObject value; - for (Descriptors.FieldDescriptor fieldDescriptor : builder.getAllFields().keySet()) { + for (Descriptors.FieldDescriptor fieldDescriptor : this.descriptor.getFields()) { if (fieldDescriptor.isRepeated()) { - dup.repeatedFields.put(fieldDescriptor, getRepeatedField(context, fieldDescriptor)); - } else if (builder.hasField(fieldDescriptor)) { - dup.fields.put(fieldDescriptor, wrapField(context, fieldDescriptor, builder.getField(fieldDescriptor))); + dup.addRepeatedField(fieldDescriptor, this.getRepeatedField(context, fieldDescriptor)); + } else if (fields.containsKey(fieldDescriptor)) { + dup.fields.put(fieldDescriptor, fields.get(fieldDescriptor)); + } else if (this.builder.hasField(fieldDescriptor)) { + dup.fields.put(fieldDescriptor, wrapField(context, fieldDescriptor, this.builder.getField(fieldDescriptor))); } } - for (Descriptors.FieldDescriptor fieldDescriptor : fields.keySet()) { - dup.fields.put(fieldDescriptor, fields.get(fieldDescriptor)); - } for (Descriptors.FieldDescriptor fieldDescriptor : maps.keySet()) { dup.maps.put(fieldDescriptor, maps.get(fieldDescriptor)); } @@ -411,6 +410,7 @@ public class RubyMessage extends RubyObject { for (int i = 0; i < count; i++) { ret.push(context, wrapField(context, fieldDescriptor, this.builder.getRepeatedField(fieldDescriptor, i))); } + addRepeatedField(fieldDescriptor, ret); return ret; } @@ -659,14 +659,14 @@ public class RubyMessage extends RubyObject { } else { Descriptors.FieldDescriptor.Type fieldType = fieldDescriptor.getType(); IRubyObject typeClass = context.runtime.getObject(); + boolean addValue = true; if (fieldType == Descriptors.FieldDescriptor.Type.MESSAGE) { typeClass = ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)).msgclass(context); + if (value.isNil()){ + addValue = false; + } } else if (fieldType == Descriptors.FieldDescriptor.Type.ENUM) { typeClass = ((RubyEnumDescriptor) getDescriptorForField(context, fieldDescriptor)).enummodule(context); - } - Utils.checkType(context, fieldType, value, (RubyModule) typeClass); - // Convert integer enum to symbol - if (fieldType == Descriptors.FieldDescriptor.Type.ENUM) { Descriptors.EnumDescriptor enumDescriptor = fieldDescriptor.getEnumType(); if (Utils.isRubyNum(value)) { Descriptors.EnumValueDescriptor val = @@ -674,7 +674,12 @@ public class RubyMessage extends RubyObject { if (val.getIndex() != -1) value = context.runtime.newSymbol(val.getName()); } } - this.fields.put(fieldDescriptor, value); + if (addValue) { + Utils.checkType(context, fieldType, value, (RubyModule) typeClass); + this.fields.put(fieldDescriptor, value); + } else { + this.fields.remove(fieldDescriptor); + } } } return context.runtime.getNil(); diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java index 9788317a..84bf8956 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java @@ -108,8 +108,9 @@ public class RubyRepeatedField extends RubyObject { */ @JRubyMethod(name = "[]=") public IRubyObject indexSet(ThreadContext context, IRubyObject index, IRubyObject value) { + int arrIndex = normalizeArrayIndex(index); Utils.checkType(context, fieldType, value, (RubyModule) typeClass); - this.storage.set(RubyNumeric.num2int(index), value); + this.storage.set(arrIndex, value); return context.runtime.getNil(); } @@ -117,12 +118,15 @@ public class RubyRepeatedField extends RubyObject { * call-seq: * RepeatedField.[](index) => value * - * Accesses the element at the given index. Throws an exception on out-of-bounds - * errors. + * Accesses the element at the given index. Returns nil on out-of-bounds */ @JRubyMethod(name = "[]") public IRubyObject index(ThreadContext context, IRubyObject index) { - return this.storage.eltInternal(RubyNumeric.num2int(index)); + int arrIndex = normalizeArrayIndex(index); + if (arrIndex < 0 || arrIndex >= this.storage.size()) { + return context.runtime.getNil(); + } + return this.storage.eltInternal(arrIndex); } /* @@ -134,8 +138,7 @@ public class RubyRepeatedField extends RubyObject { @JRubyMethod(rest = true) public IRubyObject insert(ThreadContext context, IRubyObject[] args) { for (int i = 0; i < args.length; i++) { - Utils.checkType(context, fieldType, args[i], (RubyModule) typeClass); - this.storage.add(args[i]); + push(context, args[i]); } return context.runtime.getNil(); } @@ -385,6 +388,15 @@ public class RubyRepeatedField extends RubyObject { } } + private int normalizeArrayIndex(IRubyObject index) { + int arrIndex = RubyNumeric.num2int(index); + int arrSize = this.storage.size(); + if (arrIndex < 0 && arrSize > 0) { + arrIndex = arrSize + arrIndex; + } + return arrIndex; + } + private RubyArray storage; private Descriptors.FieldDescriptor.Type fieldType; private IRubyObject typeClass; diff --git a/ruby/tests/basic.rb b/ruby/tests/basic.rb index 1c3fb62c..1c2a03dc 100644 --- a/ruby/tests/basic.rb +++ b/ruby/tests/basic.rb @@ -154,6 +154,8 @@ module BasicTest assert m.optional_bytes == "world" m.optional_msg = TestMessage2.new(:foo => 42) assert m.optional_msg == TestMessage2.new(:foo => 42) + m.optional_msg = nil + assert m.optional_msg == nil end def test_ctor_args @@ -314,6 +316,17 @@ module BasicTest assert l4 == [0, 0, 0, 0, 0, 42, 100, 101, 102] end + def test_parent_rptfield + #make sure we set the RepeatedField and can add to it + m = TestMessage.new + assert m.repeated_string == [] + m.repeated_string << 'ok' + m.repeated_string.push('ok2') + assert m.repeated_string == ['ok', 'ok2'] + m.repeated_string += ['ok3'] + assert m.repeated_string == ['ok', 'ok2', 'ok3'] + end + def test_rptfield_msg l = Google::Protobuf::RepeatedField.new(:message, TestMessage) l.push TestMessage.new @@ -377,6 +390,39 @@ module BasicTest end end + def test_rptfield_array_ducktyping + l = Google::Protobuf::RepeatedField.new(:int32) + length_methods = %w(count length size) + length_methods.each do |lm| + assert l.send(lm) == 0 + end + # out of bounds returns a nil + assert l[0] == nil + assert l[1] == nil + assert l[-1] == nil + l.push 4 + length_methods.each do |lm| + assert l.send(lm) == 1 + end + assert l[0] == 4 + assert l[1] == nil + assert l[-1] == 4 + assert l[-2] == nil + + l.push 2 + length_methods.each do |lm| + assert l.send(lm) == 2 + end + assert l[0] == 4 + assert l[1] == 2 + assert l[2] == nil + assert l[-1] == 2 + assert l[-2] == 4 + assert l[-3] == nil + + #adding out of scope will backfill with empty objects + end + def test_map_basic # allowed key types: # :int32, :int64, :uint32, :uint64, :bool, :string, :bytes. @@ -712,9 +758,12 @@ module BasicTest m = TestMessage.new m.optional_string = "hello" m.optional_int32 = 42 - m.repeated_msg.push TestMessage2.new(:foo => 100) - m.repeated_msg.push TestMessage2.new(:foo => 200) - + tm1 = TestMessage2.new(:foo => 100) + tm2 = TestMessage2.new(:foo => 200) + m.repeated_msg.push tm1 + assert m.repeated_msg[-1] == tm1 + m.repeated_msg.push tm2 + assert m.repeated_msg[-1] == tm2 m2 = m.dup assert m == m2 m.optional_int32 += 1 @@ -827,7 +876,6 @@ module BasicTest assert m['a.b'] == 4 end - def test_int_ranges m = TestMessage.new @@ -933,7 +981,6 @@ module BasicTest assert_raise RangeError do m.optional_uint64 = 1.5 end - end def test_stress_test diff --git a/src/Makefile.am b/src/Makefile.am index 049583f5..12826d95 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,7 +24,17 @@ AM_LDFLAGS = $(PTHREAD_CFLAGS) # If I say "dist_include_DATA", automake complains that $(includedir) is not # a "legitimate" directory for DATA. Screw you, automake. protodir = $(includedir) -nobase_dist_proto_DATA = google/protobuf/descriptor.proto \ +nobase_dist_proto_DATA = google/protobuf/descriptor.proto \ + google/protobuf/any.proto \ + google/protobuf/api.proto \ + google/protobuf/duration.proto \ + google/protobuf/empty.proto \ + google/protobuf/field_mask.proto \ + google/protobuf/source_context.proto \ + google/protobuf/struct.proto \ + google/protobuf/timestamp.proto \ + google/protobuf/type.proto \ + google/protobuf/wrappers.proto \ google/protobuf/compiler/plugin.proto # Not sure why these don't get cleaned automatically. @@ -125,6 +135,7 @@ nobase_include_HEADERS = \ google/protobuf/compiler/java/java_generator.h \ google/protobuf/compiler/java/java_names.h \ google/protobuf/compiler/javanano/javanano_generator.h \ + google/protobuf/compiler/objectivec/objectivec_generator.h \ google/protobuf/compiler/python/python_generator.h \ google/protobuf/compiler/ruby/ruby_generator.h \ google/protobuf/compiler/csharp/csharp_generator.h @@ -288,6 +299,29 @@ libprotoc_la_SOURCES = \ google/protobuf/compiler/javanano/javanano_params.h \ google/protobuf/compiler/javanano/javanano_primitive_field.cc \ google/protobuf/compiler/javanano/javanano_primitive_field.h \ + google/protobuf/compiler/objectivec/objectivec_enum.cc \ + google/protobuf/compiler/objectivec/objectivec_enum.h \ + google/protobuf/compiler/objectivec/objectivec_enum_field.cc \ + google/protobuf/compiler/objectivec/objectivec_enum_field.h \ + google/protobuf/compiler/objectivec/objectivec_extension.cc \ + google/protobuf/compiler/objectivec/objectivec_extension.h \ + google/protobuf/compiler/objectivec/objectivec_field.cc \ + google/protobuf/compiler/objectivec/objectivec_field.h \ + google/protobuf/compiler/objectivec/objectivec_file.cc \ + google/protobuf/compiler/objectivec/objectivec_file.h \ + google/protobuf/compiler/objectivec/objectivec_generator.cc \ + google/protobuf/compiler/objectivec/objectivec_helpers.cc \ + google/protobuf/compiler/objectivec/objectivec_helpers.h \ + google/protobuf/compiler/objectivec/objectivec_map_field.cc \ + google/protobuf/compiler/objectivec/objectivec_map_field.h \ + google/protobuf/compiler/objectivec/objectivec_message.cc \ + google/protobuf/compiler/objectivec/objectivec_message.h \ + google/protobuf/compiler/objectivec/objectivec_message_field.cc \ + google/protobuf/compiler/objectivec/objectivec_message_field.h \ + google/protobuf/compiler/objectivec/objectivec_oneof.cc \ + google/protobuf/compiler/objectivec/objectivec_oneof.h \ + google/protobuf/compiler/objectivec/objectivec_primitive_field.cc \ + google/protobuf/compiler/objectivec/objectivec_primitive_field.h \ google/protobuf/compiler/python/python_generator.cc \ google/protobuf/compiler/ruby/ruby_generator.cc \ google/protobuf/compiler/csharp/csharp_enum.cc \ @@ -521,6 +555,7 @@ protobuf_test_SOURCES = \ google/protobuf/compiler/cpp/cpp_plugin_unittest.cc \ google/protobuf/compiler/java/java_plugin_unittest.cc \ google/protobuf/compiler/java/java_doc_comment_unittest.cc \ + google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc \ google/protobuf/compiler/python/python_plugin_unittest.cc \ google/protobuf/compiler/ruby/ruby_generator_unittest.cc \ google/protobuf/compiler/csharp/csharp_generator_unittest.cc \ diff --git a/src/google/protobuf/any.proto b/src/google/protobuf/any.proto index 5f29e01e..e1780fe5 100644 --- a/src/google/protobuf/any.proto +++ b/src/google/protobuf/any.proto @@ -36,11 +36,14 @@ option java_multiple_files = true; option java_outer_classname = "AnyProto"; option java_package = "com.google.protobuf"; option csharp_namespace = "Google.ProtocolBuffers"; +option objc_class_prefix = "GPB"; + // `Any` contains an arbitrary serialized message along with a URL // that describes the type of the serialized message. // -// +// The proto runtimes and/or compiler will eventually +// provide utilities to pack/unpack Any values (projected Q1/15). // // # JSON // The JSON representation of an `Any` value uses the regular @@ -76,21 +79,24 @@ message Any { // For URLs which use the schema `http`, `https`, or no schema, the // following restrictions and interpretations apply: // - // * If no schema is provided, https is assumed. + // * If no schema is provided, `https` is assumed. // * The last segment of the URL's path must represent the fully // qualified name of the type (as in `path/google.protobuf.Duration`). // * An HTTP GET on the URL must yield a [google.protobuf.Type][google.protobuf.Type] // value in binary format, or produce an error. // * Applications are allowed to cache lookup results based on the // URL, or have them precompiled into a binary to avoid any - // lookup. Therefore, binary compatibility need to be preserved + // lookup. Therefore, binary compatibility needs to be preserved // on changes to types. (Use versioned type names to manage // breaking changes.) // // Schemas other than `http`, `https` (or the empty schema) might be // used with implementation specific semantics. // - // + // Types originating from the `google.*` package + // namespace should use `type.googleapis.com/full.type.name` (without + // schema and path). A type service will eventually become available which + // serves those URLs (projected Q2/15). string type_url = 1; // Must be valid serialized data of the above specified type. diff --git a/src/google/protobuf/api.proto b/src/google/protobuf/api.proto new file mode 100644 index 00000000..f368c24d --- /dev/null +++ b/src/google/protobuf/api.proto @@ -0,0 +1,105 @@ +// 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 google.protobuf; + +import "google/protobuf/source_context.proto"; +import "google/protobuf/type.proto"; + +option java_multiple_files = true; +option java_outer_classname = "ApiProto"; +option java_package = "com.google.protobuf"; +option objc_class_prefix = "GPB"; + + +// Api is a light-weight descriptor for a protocol buffer service. +message Api { + // The fully qualified name of this api, including package name + // followed by the api's simple name. + string name = 1; + + // The methods of this api, in unspecified order. + repeated Method methods = 2; + + // Any metadata attached to the API. + repeated Option options = 3; + + // A version string for this api. If specified, must have the form + // `major-version.minor-version`, as in `1.10`. If the minor version + // is omitted, it defaults to zero. If the entire version field is + // empty, the major version is derived from the package name, as + // outlined below. If the field is not empty, the version in the + // package name will be verified to be consistent with what is + // provided here. + // + // The versioning schema uses [semantic + // versioning](http://semver.org) where the major version number + // indicates a breaking change and the minor version an additive, + // non-breaking change. Both version numbers are signals to users + // what to expect from different versions, and should be carefully + // chosen based on the product plan. + // + // The major version is also reflected in the package name of the + // API, which must end in `v<major-version>`, as in + // `google.feature.v1`. For major versions 0 and 1, the suffix can + // be omitted. Zero major versions must only be used for + // experimental, none-GA apis. + // + // See also: [design doc](http://go/api-versioning). + // + // + string version = 4; + + // Source context for the protocol buffer service represented by this + // message. + SourceContext source_context = 5; +} + +// Method represents a method of an api. +message Method { + // The simple name of this method. + string name = 1; + + // A URL of the input message type. + string request_type_url = 2; + + // If true, the request is streamed. + bool request_streaming = 3; + + // The URL of the output message type. + string response_type_url = 4; + + // If true, the response is streamed. + bool response_streaming = 5; + + // Any metadata attached to the method. + repeated Option options = 6; +} diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc index bda37413..f7059d26 100755 --- a/src/google/protobuf/arena.cc +++ b/src/google/protobuf/arena.cc @@ -29,6 +29,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <google/protobuf/arena.h> +#include <google/protobuf/stubs/common.h> #ifdef ADDRESS_SANITIZER #include <sanitizer/asan_interface.h> @@ -43,6 +44,12 @@ Arena::ThreadCache& Arena::thread_cache() { static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_ = { -1, NULL }; return thread_cache_; } +#elif defined(GOOGLE_PROTOBUF_OS_ANDROID) || defined(GOOGLE_PROTOBUF_OS_IPHONE) +Arena::ThreadCache& Arena::thread_cache() { + static internal::ThreadLocalStorage<ThreadCache>* thread_cache_ = + new internal::ThreadLocalStorage<ThreadCache>(); + return *thread_cache_->Get(); +} #else GOOGLE_THREAD_LOCAL Arena::ThreadCache Arena::thread_cache_ = { -1, NULL }; #endif diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h index bb15e80c..b48bef92 100644 --- a/src/google/protobuf/arena.h +++ b/src/google/protobuf/arena.h @@ -373,6 +373,11 @@ class LIBPROTOBUF_EXPORT Arena { // Thread local variables cannot be exposed through DLL interface but we can // wrap them in static functions. static ThreadCache& thread_cache(); +#elif defined(GOOGLE_PROTOBUF_OS_ANDROID) || defined(GOOGLE_PROTOBUF_OS_IPHONE) + // Android ndk does not support __thread keyword so we use a custom thread + // local storage class we implemented. + // iOS also does not support the __thread keyword. + static ThreadCache& thread_cache(); #else static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_; static ThreadCache& thread_cache() { return thread_cache_; } diff --git a/src/google/protobuf/arena_nc_test.py b/src/google/protobuf/arena_nc_test.py index fc510a48..f390df36 100644 --- a/src/google/protobuf/arena_nc_test.py +++ b/src/google/protobuf/arena_nc_test.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/env python # # Protocol Buffers - Google's data interchange format # Copyright 2008 Google Inc. All rights reserved. diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc index a2cbbdc6..e284c791 100644 --- a/src/google/protobuf/compiler/command_line_interface_unittest.cc +++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc @@ -288,6 +288,7 @@ void CommandLineInterfaceTest::Run(const string& command) { if (!disallow_plugins_) { cli_.AllowPlugins("prefix-"); +#ifndef GOOGLE_THIRD_PARTY_PROTOBUF const char* possible_paths[] = { // When building with shared libraries, libtool hides the real executable // in .libs and puts a fake wrapper in the current directory. @@ -316,6 +317,11 @@ void CommandLineInterfaceTest::Run(const string& command) { } if (plugin_path.empty()) { +#else + string plugin_path = "third_party/protobuf/test_plugin"; + + if (access(plugin_path.c_str(), F_OK) != 0) { +#endif // GOOGLE_THIRD_PARTY_PROTOBUF GOOGLE_LOG(ERROR) << "Plugin executable not found. Plugin tests are likely to fail."; } else { diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index cc758cf5..9d14a924 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -1392,6 +1392,12 @@ class OneofTest : public testing::Test { case unittest::TestOneof2::kFooString: EXPECT_TRUE(message.has_foo_string()); break; + case unittest::TestOneof2::kFooCord: + EXPECT_TRUE(message.has_foo_cord()); + break; + case unittest::TestOneof2::kFooStringPiece: + EXPECT_TRUE(message.has_foo_string_piece()); + break; case unittest::TestOneof2::kFooBytes: EXPECT_TRUE(message.has_foo_bytes()); break; @@ -1404,6 +1410,9 @@ class OneofTest : public testing::Test { case unittest::TestOneof2::kFoogroup: EXPECT_TRUE(message.has_foogroup()); break; + case unittest::TestOneof2::kFooLazyMessage: + EXPECT_TRUE(message.has_foo_lazy_message()); + break; case unittest::TestOneof2::FOO_NOT_SET: break; } diff --git a/src/google/protobuf/compiler/java/java_extension.cc b/src/google/protobuf/compiler/java/java_extension.cc index 27cf416b..4db7085e 100644 --- a/src/google/protobuf/compiler/java/java_extension.cc +++ b/src/google/protobuf/compiler/java/java_extension.cc @@ -181,8 +181,9 @@ void ImmutableExtensionGenerator::Generate(io::Printer* printer) { } } -void ImmutableExtensionGenerator::GenerateNonNestedInitializationCode( +int ImmutableExtensionGenerator::GenerateNonNestedInitializationCode( io::Printer* printer) { + int bytecode_estimate = 0; if (descriptor_->extension_scope() == NULL && HasDescriptorMethods(descriptor_->file())) { // Only applies to non-nested, non-lite extensions. @@ -190,15 +191,18 @@ void ImmutableExtensionGenerator::GenerateNonNestedInitializationCode( "$name$.internalInit(descriptor.getExtensions().get($index$));\n", "name", UnderscoresToCamelCase(descriptor_), "index", SimpleItoa(descriptor_->index())); + bytecode_estimate += 21; } + return bytecode_estimate; } -void ImmutableExtensionGenerator::GenerateRegistrationCode( +int ImmutableExtensionGenerator::GenerateRegistrationCode( io::Printer* printer) { printer->Print( "registry.add($scope$.$name$);\n", "scope", scope_, "name", UnderscoresToCamelCase(descriptor_)); + return 7; } } // namespace java diff --git a/src/google/protobuf/compiler/java/java_extension.h b/src/google/protobuf/compiler/java/java_extension.h index f1701fb5..bdd42263 100644 --- a/src/google/protobuf/compiler/java/java_extension.h +++ b/src/google/protobuf/compiler/java/java_extension.h @@ -67,8 +67,12 @@ class ExtensionGenerator { virtual ~ExtensionGenerator() {} virtual void Generate(io::Printer* printer) = 0; - virtual void GenerateNonNestedInitializationCode(io::Printer* printer) = 0; - virtual void GenerateRegistrationCode(io::Printer* printer) = 0; + + // Returns an estimate of the number of bytes the printed code will compile to + virtual int GenerateNonNestedInitializationCode(io::Printer* printer) = 0; + + // Returns an estimate of the number of bytes the printed code will compile to + virtual int GenerateRegistrationCode(io::Printer* printer) = 0; protected: static void InitTemplateVars(const FieldDescriptor* descriptor, @@ -88,8 +92,8 @@ class ImmutableExtensionGenerator : public ExtensionGenerator { virtual ~ImmutableExtensionGenerator(); virtual void Generate(io::Printer* printer); - virtual void GenerateNonNestedInitializationCode(io::Printer* printer); - virtual void GenerateRegistrationCode(io::Printer* printer); + virtual int GenerateNonNestedInitializationCode(io::Printer* printer); + virtual int GenerateRegistrationCode(io::Printer* printer); protected: const FieldDescriptor* descriptor_; diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc index f1e3cf67..4a1f4529 100644 --- a/src/google/protobuf/compiler/java/java_file.cc +++ b/src/google/protobuf/compiler/java/java_file.cc @@ -35,6 +35,7 @@ #include <google/protobuf/compiler/java/java_file.h> #include <memory> +#include <set> #ifndef _SHARED_PTR_H #include <google/protobuf/stubs/shared_ptr.h> #endif @@ -62,6 +63,19 @@ namespace java { namespace { +struct FieldDescriptorCompare { + bool operator ()(const FieldDescriptor* f1, const FieldDescriptor* f2) { + if(f1 == NULL) { + return false; + } + if(f2 == NULL) { + return true; + } + return f1->full_name() < f2->full_name(); + } +}; + +typedef std::set<const FieldDescriptor*, FieldDescriptorCompare> FieldDescriptorSet; // Recursively searches the given message to collect extensions. // Returns true if all the extensions can be recognized. The extensions will be @@ -69,7 +83,7 @@ namespace { // Returns false when there are unknown fields, in which case the data in the // extensions output parameter is not reliable and should be discarded. bool CollectExtensions(const Message& message, - vector<const FieldDescriptor*>* extensions) { + FieldDescriptorSet* extensions) { const Reflection* reflection = message.GetReflection(); // There are unknown fields that could be extensions, thus this call fails. @@ -79,7 +93,7 @@ bool CollectExtensions(const Message& message, reflection->ListFields(message, &fields); for (int i = 0; i < fields.size(); i++) { - if (fields[i]->is_extension()) extensions->push_back(fields[i]); + if (fields[i]->is_extension()) extensions->insert(fields[i]); if (GetJavaType(fields[i]) == JAVATYPE_MESSAGE) { if (fields[i]->is_repeated()) { @@ -106,7 +120,7 @@ bool CollectExtensions(const Message& message, // in order to handle this case. void CollectExtensions(const FileDescriptorProto& file_proto, const DescriptorPool& alternate_pool, - vector<const FieldDescriptor*>* extensions, + FieldDescriptorSet* extensions, const string& file_data) { if (!CollectExtensions(file_proto, extensions)) { // There are unknown fields in the file_proto, which are probably @@ -139,6 +153,36 @@ void CollectExtensions(const FileDescriptorProto& file_proto, } } +// Our static initialization methods can become very, very large. +// So large that if we aren't careful we end up blowing the JVM's +// 64K bytes of bytecode/method. Fortunately, since these static +// methods are executed only once near the beginning of a program, +// there's usually plenty of stack space available and we can +// extend our methods by simply chaining them to another method +// with a tail call. This inserts the sequence call-next-method, +// end this one, begin-next-method as needed. +void MaybeRestartJavaMethod(io::Printer* printer, + int *bytecode_estimate, + int *method_num, + const char *chain_statement, + const char *method_decl) { + + // The goal here is to stay under 64K bytes of jvm bytecode/method, + // since otherwise we hit a hardcoded limit in the jvm and javac will + // then fail with the error "code too large". This limit lets our + // estimates be off by a factor of two and still we're okay. + static const int bytesPerMethod = 1<<15; // aka 32K + + if ((*bytecode_estimate) > bytesPerMethod) { + ++(*method_num); + printer->Print(chain_statement, "method_num", SimpleItoa(*method_num)); + printer->Outdent(); + printer->Print("}\n"); + printer->Print(method_decl, "method_num", SimpleItoa(*method_num)); + printer->Indent(); + *bytecode_estimate = 0; + } +} } // namespace @@ -270,9 +314,16 @@ void FileGenerator::Generate(io::Printer* printer) { printer->Print( "static {\n"); printer->Indent(); + int bytecode_estimate = 0; + int method_num = 0; for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->GenerateStaticVariableInitializers(printer); + bytecode_estimate += message_generators_[i]->GenerateStaticVariableInitializers(printer); + MaybeRestartJavaMethod( + printer, + &bytecode_estimate, &method_num, + "_clinit_autosplit_$method_num$();\n", + "private static void _clinit_autosplit_$method_num$() {\n"); } printer->Outdent(); @@ -303,12 +354,24 @@ void FileGenerator::GenerateDescriptorInitializationCodeForImmutable( SharedCodeGenerator shared_code_generator(file_); shared_code_generator.GenerateDescriptors(printer); + int bytecode_estimate = 0; + int method_num = 0; for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->GenerateStaticVariableInitializers(printer); + bytecode_estimate += message_generators_[i]->GenerateStaticVariableInitializers(printer); + MaybeRestartJavaMethod( + printer, + &bytecode_estimate, &method_num, + "_clinit_autosplit_dinit_$method_num$();\n", + "private static void _clinit_autosplit_dinit_$method_num$() {\n"); } for (int i = 0; i < file_->extension_count(); i++) { - extension_generators_[i]->GenerateNonNestedInitializationCode(printer); + bytecode_estimate += extension_generators_[i]->GenerateNonNestedInitializationCode(printer); + MaybeRestartJavaMethod( + printer, + &bytecode_estimate, &method_num, + "_clinit_autosplit_dinit_$method_num$();\n", + "private static void _clinit_autosplit_dinit_$method_num$() {\n"); } // Proto compiler builds a DescriptorPool, which holds all the descriptors to @@ -330,7 +393,7 @@ void FileGenerator::GenerateDescriptorInitializationCodeForImmutable( file_->CopyTo(&file_proto); string file_data; file_proto.SerializeToString(&file_data); - vector<const FieldDescriptor*> extensions; + FieldDescriptorSet extensions; CollectExtensions(file_proto, *file_->pool(), &extensions, file_data); if (extensions.size() > 0) { @@ -339,10 +402,17 @@ void FileGenerator::GenerateDescriptorInitializationCodeForImmutable( printer->Print( "com.google.protobuf.ExtensionRegistry registry =\n" " com.google.protobuf.ExtensionRegistry.newInstance();\n"); - for (int i = 0; i < extensions.size(); i++) { + FieldDescriptorSet::iterator it; + for (it = extensions.begin(); it != extensions.end(); it++) { google::protobuf::scoped_ptr<ExtensionGenerator> generator( - generator_factory_->NewExtensionGenerator(extensions[i])); - generator->GenerateRegistrationCode(printer); + generator_factory_->NewExtensionGenerator(*it)); + bytecode_estimate += generator->GenerateRegistrationCode(printer); + MaybeRestartJavaMethod( + printer, + &bytecode_estimate, &method_num, + "_clinit_autosplit_dinit_$method_num$(registry);\n", + "private static void _clinit_autosplit_dinit_$method_num$(\n" + " com.google.protobuf.ExtensionRegistry registry) {\n"); } printer->Print( "com.google.protobuf.Descriptors.FileDescriptor\n" @@ -394,7 +464,7 @@ void FileGenerator::GenerateDescriptorInitializationCodeForMutable(io::Printer* file_->CopyTo(&file_proto); string file_data; file_proto.SerializeToString(&file_data); - vector<const FieldDescriptor*> extensions; + FieldDescriptorSet extensions; CollectExtensions(file_proto, *file_->pool(), &extensions, file_data); if (extensions.size() > 0) { diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc index e982a17b..63df10b4 100644 --- a/src/google/protobuf/compiler/java/java_message.cc +++ b/src/google/protobuf/compiler/java/java_message.cc @@ -124,7 +124,7 @@ void ImmutableMessageGenerator::GenerateStaticVariables(io::Printer* printer) { // The descriptor for this type. printer->Print(vars, - "$private$static final com.google.protobuf.Descriptors.Descriptor\n" + "$private$static com.google.protobuf.Descriptors.Descriptor\n" " internal_$identifier$_descriptor;\n"); // And the FieldAccessorTable. @@ -139,8 +139,9 @@ void ImmutableMessageGenerator::GenerateStaticVariables(io::Printer* printer) { } } -void ImmutableMessageGenerator::GenerateStaticVariableInitializers( +int ImmutableMessageGenerator::GenerateStaticVariableInitializers( io::Printer* printer) { + int bytecode_estimate = 0; if (HasDescriptorMethods(descriptor_)) { map<string, string> vars; vars["identifier"] = UniqueFileScopeIdentifier(descriptor_); @@ -156,22 +157,25 @@ void ImmutableMessageGenerator::GenerateStaticVariableInitializers( printer->Print(vars, "internal_$identifier$_descriptor =\n" " getDescriptor().getMessageTypes().get($index$);\n"); + bytecode_estimate += 30; } else { printer->Print(vars, "internal_$identifier$_descriptor =\n" " internal_$parent$_descriptor.getNestedTypes().get($index$);\n"); + bytecode_estimate += 30; } // And the FieldAccessorTable. - GenerateFieldAccessorTableInitializer(printer); + bytecode_estimate += GenerateFieldAccessorTableInitializer(printer); } // Generate static member initializers for all nested types. for (int i = 0; i < descriptor_->nested_type_count(); i++) { // TODO(kenton): Reuse MessageGenerator objects? - ImmutableMessageGenerator(descriptor_->nested_type(i), context_) + bytecode_estimate += ImmutableMessageGenerator(descriptor_->nested_type(i), context_) .GenerateStaticVariableInitializers(printer); } + return bytecode_estimate; } void ImmutableMessageGenerator:: @@ -191,8 +195,9 @@ GenerateFieldAccessorTable(io::Printer* printer) { " internal_$identifier$_fieldAccessorTable;\n"); } -void ImmutableMessageGenerator:: +int ImmutableMessageGenerator:: GenerateFieldAccessorTableInitializer(io::Printer* printer) { + int bytecode_estimate = 10; printer->Print( "internal_$identifier$_fieldAccessorTable = new\n" " com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n" @@ -203,6 +208,7 @@ GenerateFieldAccessorTableInitializer(io::Printer* printer) { for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + bytecode_estimate += 6; printer->Print( "\"$field_name$\", ", "field_name", info->capitalized_name); @@ -210,11 +216,13 @@ GenerateFieldAccessorTableInitializer(io::Printer* printer) { for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { const OneofDescriptor* oneof = descriptor_->oneof_decl(i); const OneofGeneratorInfo* info = context_->GetOneofGeneratorInfo(oneof); + bytecode_estimate += 6; printer->Print( "\"$oneof_name$\", ", "oneof_name", info->capitalized_name); } printer->Print("});\n"); + return bytecode_estimate; } // =================================================================== diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h index 016fdd5d..58dd5f99 100644 --- a/src/google/protobuf/compiler/java/java_message.h +++ b/src/google/protobuf/compiler/java/java_message.h @@ -67,8 +67,8 @@ class MessageGenerator { virtual void GenerateStaticVariables(io::Printer* printer) = 0; // Output code which initializes the static variables generated by - // GenerateStaticVariables(). - virtual void GenerateStaticVariableInitializers(io::Printer* printer) = 0; + // GenerateStaticVariables(). Returns an estimate of bytecode size. + virtual int GenerateStaticVariableInitializers(io::Printer* printer) = 0; // Generate the class itself. virtual void Generate(io::Printer* printer) = 0; @@ -97,7 +97,9 @@ class ImmutableMessageGenerator : public MessageGenerator { virtual void GenerateInterface(io::Printer* printer); virtual void GenerateExtensionRegistrationCode(io::Printer* printer); virtual void GenerateStaticVariables(io::Printer* printer); - virtual void GenerateStaticVariableInitializers(io::Printer* printer); + + // Returns an estimate of the number of bytes the printed code will compile to + virtual int GenerateStaticVariableInitializers(io::Printer* printer); private: enum UseMemoization { @@ -106,7 +108,9 @@ class ImmutableMessageGenerator : public MessageGenerator { }; void GenerateFieldAccessorTable(io::Printer* printer); - void GenerateFieldAccessorTableInitializer(io::Printer* printer); + + // Returns an estimate of the number of bytes the printed code will compile to + int GenerateFieldAccessorTableInitializer(io::Printer* printer); void GenerateMessageSerializationMethods(io::Printer* printer); void GenerateParseFromMethods(io::Printer* printer); diff --git a/src/google/protobuf/compiler/javanano/javanano_enum.cc b/src/google/protobuf/compiler/javanano/javanano_enum.cc index f934b05f..c6e8dfe9 100644 --- a/src/google/protobuf/compiler/javanano/javanano_enum.cc +++ b/src/google/protobuf/compiler/javanano/javanano_enum.cc @@ -73,13 +73,45 @@ void EnumGenerator::Generate(io::Printer* printer) { "// enum $classname$\n", "classname", descriptor_->name()); + const string classname = RenameJavaKeywords(descriptor_->name()); + // Start of container interface + // If generating intdefs, we use the container interface as the intdef if + // present. Otherwise, we just make an empty @interface parallel to the + // constants. + bool use_intdef = params_.generate_intdefs(); bool use_shell_class = params_.java_enum_style(); - if (use_shell_class) { - printer->Print( - "public interface $classname$ {\n", - "classname", RenameJavaKeywords(descriptor_->name())); + if (use_intdef) { + // @IntDef annotation so tools can enforce correctness + // Annotations will be discarded by the compiler + printer->Print("@java.lang.annotation.Retention(" + "java.lang.annotation.RetentionPolicy.SOURCE)\n" + "@android.support.annotation.IntDef({\n"); printer->Indent(); + for (int i = 0; i < canonical_values_.size(); i++) { + const string constant_name = + RenameJavaKeywords(canonical_values_[i]->name()); + if (use_shell_class) { + printer->Print("$classname$.$name$,\n", + "classname", classname, + "name", constant_name); + } else { + printer->Print("$name$,\n", "name", constant_name); + } + } + printer->Outdent(); + printer->Print("})\n"); + } + if (use_shell_class || use_intdef) { + printer->Print( + "public $at_for_intdef$interface $classname$ {\n", + "classname", classname, + "at_for_intdef", use_intdef ? "@" : ""); + if (use_shell_class) { + printer->Indent(); + } else { + printer->Print("}\n\n"); + } } // Canonical values diff --git a/src/google/protobuf/compiler/javanano/javanano_enum_field.cc b/src/google/protobuf/compiler/javanano/javanano_enum_field.cc index 8a59d323..7666db38 100644 --- a/src/google/protobuf/compiler/javanano/javanano_enum_field.cc +++ b/src/google/protobuf/compiler/javanano/javanano_enum_field.cc @@ -76,6 +76,10 @@ void SetEnumVariables(const Params& params, internal::WireFormatLite::MakeTag(descriptor->number(), internal::WireFormat::WireTypeForFieldType(descriptor->type()))); (*variables)["message_name"] = descriptor->containing_type()->name(); + const EnumDescriptor* enum_type = descriptor->enum_type(); + (*variables)["message_type_intdef"] = "@" + + ToJavaName(params, enum_type->name(), true, + enum_type->containing_type(), enum_type->file()); } void LoadEnumValues(const Params& params, @@ -116,8 +120,10 @@ EnumFieldGenerator::~EnumFieldGenerator() {} void EnumFieldGenerator:: GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const { - printer->Print(variables_, - "public $type$ $name$;\n"); + if (params_.generate_intdefs()) { + printer->Print(variables_, "$message_type_intdef$\n"); + } + printer->Print(variables_, "public $type$ $name$;\n"); if (params_.generate_has()) { printer->Print(variables_, @@ -256,12 +262,22 @@ AccessorEnumFieldGenerator::~AccessorEnumFieldGenerator() {} void AccessorEnumFieldGenerator:: GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const { + printer->Print(variables_, "private int $name$_;\n"); + if (params_.generate_intdefs()) { + printer->Print(variables_, "$message_type_intdef$\n"); + } printer->Print(variables_, - "private int $name$_;\n" "public int get$capitalized_name$() {\n" " return $name$_;\n" "}\n" - "public $message_name$ set$capitalized_name$(int value) {\n" + "public $message_name$ set$capitalized_name$("); + if (params_.generate_intdefs()) { + printer->Print(variables_, + "\n" + " $message_type_intdef$ "); + } + printer->Print(variables_, + "int value) {\n" " $name$_ = value;\n" " $set_has$;\n" " return this;\n" @@ -499,6 +515,14 @@ GenerateSerializedSizeCode(io::Printer* printer) const { } void RepeatedEnumFieldGenerator:: +GenerateFixClonedCode(io::Printer* printer) const { + printer->Print(variables_, + "if (this.$name$ != null && this.$name$.length > 0) {\n" + " cloned.$name$ = this.$name$.clone();\n" + "}\n"); +} + +void RepeatedEnumFieldGenerator:: GenerateEqualsCode(io::Printer* printer) const { printer->Print(variables_, "if (!com.google.protobuf.nano.InternalNano.equals(\n" diff --git a/src/google/protobuf/compiler/javanano/javanano_enum_field.h b/src/google/protobuf/compiler/javanano/javanano_enum_field.h index 00adc61f..b94790d6 100644 --- a/src/google/protobuf/compiler/javanano/javanano_enum_field.h +++ b/src/google/protobuf/compiler/javanano/javanano_enum_field.h @@ -106,6 +106,7 @@ class RepeatedEnumFieldGenerator : public FieldGenerator { void GenerateSerializedSizeCode(io::Printer* printer) const; void GenerateEqualsCode(io::Printer* printer) const; void GenerateHashCodeCode(io::Printer* printer) const; + void GenerateFixClonedCode(io::Printer* printer) const; private: void GenerateRepeatedDataSizeCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/javanano/javanano_extension.cc b/src/google/protobuf/compiler/javanano/javanano_extension.cc index 754ed550..0b9d1d8d 100644 --- a/src/google/protobuf/compiler/javanano/javanano_extension.cc +++ b/src/google/protobuf/compiler/javanano/javanano_extension.cc @@ -140,7 +140,7 @@ void ExtensionGenerator::Generate(io::Printer* printer) const { " com.google.protobuf.nano.Extension.create$repeated$$ext_type$(\n" " com.google.protobuf.nano.Extension.$type$,\n" " $class$.class,\n" - " $tag_params$);\n"); + " $tag_params$L);\n"); } } // namespace javanano diff --git a/src/google/protobuf/compiler/javanano/javanano_field.h b/src/google/protobuf/compiler/javanano/javanano_field.h index c2cf091c..57c221f4 100644 --- a/src/google/protobuf/compiler/javanano/javanano_field.h +++ b/src/google/protobuf/compiler/javanano/javanano_field.h @@ -83,6 +83,7 @@ class FieldGenerator { virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0; virtual void GenerateEqualsCode(io::Printer* printer) const = 0; virtual void GenerateHashCodeCode(io::Printer* printer) const = 0; + virtual void GenerateFixClonedCode(io::Printer* printer) const {} protected: const Params& params_; diff --git a/src/google/protobuf/compiler/javanano/javanano_generator.cc b/src/google/protobuf/compiler/javanano/javanano_generator.cc index b5fbcd5f..ad215cb7 100644 --- a/src/google/protobuf/compiler/javanano/javanano_generator.cc +++ b/src/google/protobuf/compiler/javanano/javanano_generator.cc @@ -152,6 +152,12 @@ bool JavaNanoGenerator::Generate(const FileDescriptor* file, params.set_ignore_services(option_value == "true"); } else if (option_name == "parcelable_messages") { params.set_parcelable_messages(option_value == "true"); + } else if (option_name == "generate_clone") { + params.set_generate_clone(option_value == "true"); + } else if (option_name == "generate_intdefs") { + params.set_generate_intdefs(option_value == "true"); + } else if (option_name == "generate_clear") { + params.set_generate_clear(option_value == "true"); } else { *error = "Ignore unknown javanano generator option: " + option_name; } diff --git a/src/google/protobuf/compiler/javanano/javanano_message.cc b/src/google/protobuf/compiler/javanano/javanano_message.cc index 707f6b84..a41da5ae 100644 --- a/src/google/protobuf/compiler/javanano/javanano_message.cc +++ b/src/google/protobuf/compiler/javanano/javanano_message.cc @@ -136,21 +136,37 @@ void MessageGenerator::Generate(io::Printer* printer) { } if (params_.store_unknown_fields() && params_.parcelable_messages()) { printer->Print( - " com.google.protobuf.nano.android.ParcelableExtendableMessageNano<$classname$> {\n", + " com.google.protobuf.nano.android.ParcelableExtendableMessageNano<$classname$>", "classname", descriptor_->name()); } else if (params_.store_unknown_fields()) { printer->Print( - " com.google.protobuf.nano.ExtendableMessageNano<$classname$> {\n", + " com.google.protobuf.nano.ExtendableMessageNano<$classname$>", "classname", descriptor_->name()); } else if (params_.parcelable_messages()) { printer->Print( - " com.google.protobuf.nano.android.ParcelableMessageNano {\n"); + " com.google.protobuf.nano.android.ParcelableMessageNano"); } else { printer->Print( - " com.google.protobuf.nano.MessageNano {\n"); + " com.google.protobuf.nano.MessageNano"); + } + if (params_.generate_clone()) { + printer->Print(" implements java.lang.Cloneable {\n"); + } else { + printer->Print(" {\n"); } printer->Indent(); + if (params_.parcelable_messages()) { + printer->Print( + "\n" + "// Used by Parcelable\n" + "@SuppressWarnings({\"unused\"})\n" + "public static final android.os.Parcelable.Creator<$classname$> CREATOR =\n" + " new com.google.protobuf.nano.android.ParcelableMessageNanoCreator<\n" + " $classname$>($classname$.class);\n", + "classname", descriptor_->name()); + } + // Nested types and extensions for (int i = 0; i < descriptor_->extension_count(); i++) { ExtensionGenerator(descriptor_->extension(i), params_).Generate(printer); @@ -288,20 +304,28 @@ void MessageGenerator::Generate(io::Printer* printer) { } printer->Print("}\n"); } else { + printer->Print( + "\n" + "public $classname$() {\n", + "classname", descriptor_->name()); if (params_.generate_clear()) { - printer->Print( - "\n" - "public $classname$() {\n" - " clear();\n" - "}\n", - "classname", descriptor_->name()); + printer->Print(" clear();\n"); + } else { + printer->Indent(); + GenerateFieldInitializers(printer); + printer->Outdent(); } + printer->Print("}\n"); } // Other methods in this class GenerateClear(printer); + if (params_.generate_clone()) { + GenerateClone(printer); + } + if (params_.generate_equals()) { GenerateEquals(printer); GenerateHashCode(printer); @@ -495,6 +519,15 @@ void MessageGenerator::GenerateClear(io::Printer* printer) { "classname", descriptor_->name()); printer->Indent(); + GenerateFieldInitializers(printer); + + printer->Outdent(); + printer->Print( + " return this;\n" + "}\n"); +} + +void MessageGenerator::GenerateFieldInitializers(io::Printer* printer) { // Clear bit fields. int totalInts = (field_generators_.total_bits() + 31) / 32; for (int i = 0; i < totalInts; i++) { @@ -520,12 +553,34 @@ void MessageGenerator::GenerateClear(io::Printer* printer) { if (params_.store_unknown_fields()) { printer->Print("unknownFieldData = null;\n"); } + printer->Print("cachedSize = -1;\n"); +} + +void MessageGenerator::GenerateClone(io::Printer* printer) { + printer->Print( + "@Override\n" + "public $classname$ clone() {\n", + "classname", descriptor_->name()); + printer->Indent(); + + printer->Print( + "$classname$ cloned;\n" + "try {\n" + " cloned = ($classname$) super.clone();\n" + "} catch (java.lang.CloneNotSupportedException e) {\n" + " throw new java.lang.AssertionError(e);\n" + "}\n", + "classname", descriptor_->name()); + + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(descriptor_->field(i)).GenerateFixClonedCode(printer); + } printer->Outdent(); printer->Print( - " cachedSize = -1;\n" - " return this;\n" - "}\n"); + " return cloned;\n" + "}\n" + "\n"); } void MessageGenerator::GenerateEquals(io::Printer* printer) { @@ -568,7 +623,11 @@ void MessageGenerator::GenerateEquals(io::Printer* printer) { if (params_.store_unknown_fields()) { printer->Print( - "return unknownFieldDataEquals(other);\n"); + "if (unknownFieldData == null || unknownFieldData.isEmpty()) {\n" + " return other.unknownFieldData == null || other.unknownFieldData.isEmpty();\n" + "} else {\n" + " return unknownFieldData.equals(other.unknownFieldData);\n" + "}"); } else { printer->Print( "return true;\n"); @@ -598,7 +657,9 @@ void MessageGenerator::GenerateHashCode(io::Printer* printer) { if (params_.store_unknown_fields()) { printer->Print( - "result = 31 * result + unknownFieldDataHashCode();\n"); + "result = 31 * result + \n" + " (unknownFieldData == null || unknownFieldData.isEmpty() ? 0 : \n" + " unknownFieldData.hashCode());\n"); } printer->Print("return result;\n"); diff --git a/src/google/protobuf/compiler/javanano/javanano_message.h b/src/google/protobuf/compiler/javanano/javanano_message.h index 6f25a3a0..281ec64f 100644 --- a/src/google/protobuf/compiler/javanano/javanano_message.h +++ b/src/google/protobuf/compiler/javanano/javanano_message.h @@ -77,8 +77,10 @@ class MessageGenerator { const FieldDescriptor* field); void GenerateClear(io::Printer* printer); + void GenerateFieldInitializers(io::Printer* printer); void GenerateEquals(io::Printer* printer); void GenerateHashCode(io::Printer* printer); + void GenerateClone(io::Printer* printer); const Params& params_; const Descriptor* descriptor_; diff --git a/src/google/protobuf/compiler/javanano/javanano_message_field.cc b/src/google/protobuf/compiler/javanano/javanano_message_field.cc index 181c4060..d1d04b52 100644 --- a/src/google/protobuf/compiler/javanano/javanano_message_field.cc +++ b/src/google/protobuf/compiler/javanano/javanano_message_field.cc @@ -127,6 +127,14 @@ GenerateSerializedSizeCode(io::Printer* printer) const { } void MessageFieldGenerator:: +GenerateFixClonedCode(io::Printer* printer) const { + printer->Print(variables_, + "if (this.$name$ != null) {\n" + " cloned.$name$ = this.$name$.clone();\n" + "}\n"); +} + +void MessageFieldGenerator:: GenerateEqualsCode(io::Printer* printer) const { printer->Print(variables_, "if (this.$name$ == null) { \n" @@ -213,6 +221,14 @@ GenerateSerializedSizeCode(io::Printer* printer) const { } void MessageOneofFieldGenerator:: +GenerateFixClonedCode(io::Printer* printer) const { + printer->Print(variables_, + "if (this.$oneof_name$ != null) {\n" + " cloned.$oneof_name$ = this.$oneof_name$.clone();\n" + "}\n"); +} + +void MessageOneofFieldGenerator:: GenerateEqualsCode(io::Printer* printer) const { GenerateOneofFieldEquals(descriptor_, variables_, printer); } @@ -313,6 +329,19 @@ GenerateSerializedSizeCode(io::Printer* printer) const { } void RepeatedMessageFieldGenerator:: +GenerateFixClonedCode(io::Printer* printer) const { + printer->Print(variables_, + "if (this.$name$ != null && this.$name$.length > 0) {\n" + " cloned.$name$ = new $type$[this.$name$.length];\n" + " for (int i = 0; i < this.$name$.length; i++) {\n" + " if (this.$name$[i] != null) {\n" + " cloned.$name$[i] = this.$name$[i].clone();\n" + " }\n" + " }\n" + "}\n"); +} + +void RepeatedMessageFieldGenerator:: GenerateEqualsCode(io::Printer* printer) const { printer->Print(variables_, "if (!com.google.protobuf.nano.InternalNano.equals(\n" diff --git a/src/google/protobuf/compiler/javanano/javanano_message_field.h b/src/google/protobuf/compiler/javanano/javanano_message_field.h index 6c615f5e..e074735c 100644 --- a/src/google/protobuf/compiler/javanano/javanano_message_field.h +++ b/src/google/protobuf/compiler/javanano/javanano_message_field.h @@ -58,6 +58,7 @@ class MessageFieldGenerator : public FieldGenerator { void GenerateSerializedSizeCode(io::Printer* printer) const; void GenerateEqualsCode(io::Printer* printer) const; void GenerateHashCodeCode(io::Printer* printer) const; + void GenerateFixClonedCode(io::Printer* printer) const; private: const FieldDescriptor* descriptor_; @@ -80,6 +81,7 @@ class MessageOneofFieldGenerator : public FieldGenerator { void GenerateSerializedSizeCode(io::Printer* printer) const; void GenerateEqualsCode(io::Printer* printer) const; void GenerateHashCodeCode(io::Printer* printer) const; + void GenerateFixClonedCode(io::Printer* printer) const; private: const FieldDescriptor* descriptor_; @@ -102,6 +104,7 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { void GenerateSerializedSizeCode(io::Printer* printer) const; void GenerateEqualsCode(io::Printer* printer) const; void GenerateHashCodeCode(io::Printer* printer) const; + void GenerateFixClonedCode(io::Printer* printer) const; private: const FieldDescriptor* descriptor_; diff --git a/src/google/protobuf/compiler/javanano/javanano_params.h b/src/google/protobuf/compiler/javanano/javanano_params.h index 4691f360..e3b4bb93 100644 --- a/src/google/protobuf/compiler/javanano/javanano_params.h +++ b/src/google/protobuf/compiler/javanano/javanano_params.h @@ -66,6 +66,8 @@ class Params { bool parcelable_messages_; bool reftypes_primitive_enums_; bool generate_clear_; + bool generate_clone_; + bool generate_intdefs_; public: Params(const string & base_name) : @@ -81,7 +83,9 @@ class Params { ignore_services_(false), parcelable_messages_(false), reftypes_primitive_enums_(false), - generate_clear_(true) { + generate_clear_(true), + generate_clone_(false), + generate_intdefs_(false) { } const string& base_name() const { @@ -231,6 +235,20 @@ class Params { bool generate_clear() const { return generate_clear_; } + + void set_generate_clone(bool value) { + generate_clone_ = value; + } + bool generate_clone() const { + return generate_clone_; + } + + void set_generate_intdefs(bool value) { + generate_intdefs_ = value; + } + bool generate_intdefs() const { + return generate_intdefs_; + } }; } // namespace javanano diff --git a/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc index 41bad0a6..978abf2c 100644 --- a/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc +++ b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc @@ -364,6 +364,14 @@ GenerateSerializedSizeCode(io::Printer* printer) const { } } +void RepeatedPrimitiveFieldGenerator:: +GenerateFixClonedCode(io::Printer* printer) const { + printer->Print(variables_, + "if (this.$name$ != null && this.$name$.length > 0) {\n" + " cloned.$name$ = this.$name$.clone();\n" + "}\n"); +} + void PrimitiveFieldGenerator:: GenerateEqualsCode(io::Printer* printer) const { // We define equality as serialized form equality. If generate_has(), diff --git a/src/google/protobuf/compiler/javanano/javanano_primitive_field.h b/src/google/protobuf/compiler/javanano/javanano_primitive_field.h index ca7116ff..a01981dd 100644 --- a/src/google/protobuf/compiler/javanano/javanano_primitive_field.h +++ b/src/google/protobuf/compiler/javanano/javanano_primitive_field.h @@ -131,6 +131,7 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator { void GenerateSerializedSizeCode(io::Printer* printer) const; void GenerateEqualsCode(io::Printer* printer) const; void GenerateHashCodeCode(io::Printer* printer) const; + void GenerateFixClonedCode(io::Printer* printer) const; private: void GenerateRepeatedDataSizeCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc index bc2da38e..4815a726 100644 --- a/src/google/protobuf/compiler/main.cc +++ b/src/google/protobuf/compiler/main.cc @@ -37,6 +37,7 @@ #include <google/protobuf/compiler/javanano/javanano_generator.h> #include <google/protobuf/compiler/ruby/ruby_generator.h> #include <google/protobuf/compiler/csharp/csharp_generator.h> +#include <google/protobuf/compiler/objectivec/objectivec_generator.h> int main(int argc, char* argv[]) { @@ -74,5 +75,10 @@ int main(int argc, char* argv[]) { cli.RegisterGenerator("--csharp_out", &csharp_generator, "Generate C# source file."); + // Objective C + google::protobuf::compiler::objectivec::ObjectiveCGenerator objc_generator; + cli.RegisterGenerator("--objc_out", &objc_generator, + "Generate Objective C header and source."); + return cli.Run(argc, argv); } diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum.cc b/src/google/protobuf/compiler/objectivec/objectivec_enum.cc new file mode 100644 index 00000000..b7c720d2 --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_enum.cc @@ -0,0 +1,199 @@ +// 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. + +#include <map> +#include <string> + +#include <google/protobuf/compiler/objectivec/objectivec_enum.h> +#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor) + : descriptor_(descriptor), + name_(EnumName(descriptor_)) { + for (int i = 0; i < descriptor_->value_count(); i++) { + const EnumValueDescriptor* value = descriptor_->value(i); + const EnumValueDescriptor* canonical_value = + descriptor_->FindValueByNumber(value->number()); + + if (value == canonical_value) { + base_values_.push_back(value); + } + all_values_.push_back(value); + } +} + +EnumGenerator::~EnumGenerator() {} + +void EnumGenerator::GenerateHeader(io::Printer* printer) { + string enum_comments; + SourceLocation location; + if (descriptor_->GetSourceLocation(&location)) { + enum_comments = BuildCommentsString(location); + } else { + enum_comments = ""; + } + + printer->Print( + "#pragma mark - Enum $name$\n" + "\n", + "name", name_); + + printer->Print("$comments$typedef GPB_ENUM($name$) {\n", + "comments", enum_comments, + "name", name_); + printer->Indent(); + + if (HasPreservingUnknownEnumSemantics(descriptor_->file())) { + // Include the unknown value. + printer->Print( + "$name$_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,\n", + "name", name_); + } + + for (int i = 0; i < all_values_.size(); i++) { + SourceLocation location; + if (all_values_[i]->GetSourceLocation(&location)) { + string comments = BuildCommentsString(location).c_str(); + if (comments.length() > 0) { + if (i > 0) { + printer->Print("\n"); + } + printer->Print(comments.c_str()); + } + } + + printer->Print( + "$name$ = $value$,\n", + "name", EnumValueName(all_values_[i]), + "value", SimpleItoa(all_values_[i]->number())); + } + printer->Outdent(); + printer->Print( + "};\n" + "\n" + "GPBEnumDescriptor *$name$_EnumDescriptor(void);\n" + "\n" + "BOOL $name$_IsValidValue(int32_t value);\n" + "\n", + "name", name_); +} + +void EnumGenerator::GenerateSource(io::Printer* printer) { + printer->Print( + "#pragma mark - Enum $name$\n" + "\n", + "name", name_); + + printer->Print( + "GPBEnumDescriptor *$name$_EnumDescriptor(void) {\n" + " static GPBEnumDescriptor *descriptor = NULL;\n" + " if (!descriptor) {\n" + " static GPBMessageEnumValueDescription values[] = {\n", + "name", name_); + printer->Indent(); + printer->Indent(); + printer->Indent(); + + // Note: For the TextFormat decode info, we can't use the enum value as + // the key because protocol buffer enums have 'allow_alias', which lets + // a value be used more than once. Instead, the index into the list of + // enum value descriptions is used. Note: start with -1 so the first one + // will be zero. + TextFormatDecodeData text_format_decode_data; + int enum_value_description_key = -1; + + for (int i = 0; i < all_values_.size(); i++) { + ++enum_value_description_key; + string short_name(EnumValueShortName(all_values_[i])); + printer->Print("{ .name = \"$short_name$\", .number = $name$ },\n", + "short_name", short_name, + "name", EnumValueName(all_values_[i])); + if (UnCamelCaseEnumShortName(short_name) != all_values_[i]->name()) { + text_format_decode_data.AddString(enum_value_description_key, short_name, + all_values_[i]->name()); + } + } + printer->Outdent(); + printer->Outdent(); + printer->Outdent(); + printer->Print(" };\n"); + if (text_format_decode_data.num_entries() == 0) { + printer->Print( + " descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n" + " values:values\n" + " valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription)\n" + " enumVerifier:$name$_IsValidValue];\n", + "name", name_); + } else { + printer->Print( + " static const char *extraTextFormatInfo = \"$extraTextFormatInfo$\";\n" + " descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n" + " values:values\n" + " valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription)\n" + " enumVerifier:$name$_IsValidValue\n" + " extraTextFormatInfo:extraTextFormatInfo];\n", + "name", name_, + "extraTextFormatInfo", CEscape(text_format_decode_data.Data())); + } + printer->Print( + " }\n" + " return descriptor;\n" + "}\n\n"); + + printer->Print( + "BOOL $name$_IsValidValue(int32_t value__) {\n" + " switch (value__) {\n", + "name", name_); + + for (int i = 0; i < base_values_.size(); i++) { + printer->Print( + " case $name$:\n", + "name", EnumValueName(base_values_[i])); + } + + printer->Print( + " return YES;\n" + " default:\n" + " return NO;\n" + " }\n" + "}\n\n"); +} +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum.h b/src/google/protobuf/compiler/objectivec/objectivec_enum.h new file mode 100644 index 00000000..2dc5547b --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_enum.h @@ -0,0 +1,73 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_H__ + +#include <string> +#include <set> +#include <vector> +#include <google/protobuf/descriptor.h> + +namespace google { +namespace protobuf { +namespace io { +class Printer; // printer.h +} +} + +namespace protobuf { +namespace compiler { +namespace objectivec { + +class EnumGenerator { + public: + EnumGenerator(const EnumDescriptor* descriptor); + ~EnumGenerator(); + + void GenerateHeader(io::Printer* printer); + void GenerateSource(io::Printer* printer); + + const string& name() const { return name_; } + + private: + const EnumDescriptor* descriptor_; + vector<const EnumValueDescriptor*> base_values_; + vector<const EnumValueDescriptor*> all_values_; + const string name_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator); +}; + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_H__ diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc new file mode 100644 index 00000000..739282b2 --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc @@ -0,0 +1,129 @@ +// 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. + +#include <map> +#include <string> + +#include <google/protobuf/compiler/objectivec/objectivec_enum_field.h> +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/compiler/objectivec/objectivec_helpers.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 objectivec { + +namespace { +void SetEnumVariables(const FieldDescriptor* descriptor, + map<string, string>* variables) { + string type = EnumName(descriptor->enum_type()); + (*variables)["storage_type"] = type; + // TODO(thomasvl): Make inclusion of descriptor compile time and output + // both of these. Note: Extensions currently have to have the EnumDescription. + (*variables)["enum_verifier"] = type + "_IsValidValue"; + (*variables)["enum_desc_func"] = type + "_EnumDescriptor"; + + const Descriptor* msg_descriptor = descriptor->containing_type(); + (*variables)["owning_message_class"] = ClassName(msg_descriptor); +} +} // namespace + +EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor) + : SingleFieldGenerator(descriptor) { + SetEnumVariables(descriptor, &variables_); +} + +EnumFieldGenerator::~EnumFieldGenerator() {} + +void EnumFieldGenerator::GenerateFieldDescriptionTypeSpecific( + io::Printer* printer) const { + // TODO(thomasvl): Output the CPP check to use descFunc or validator based + // on final compile. + printer->Print( + variables_, + " .typeSpecific.enumDescFunc = $enum_desc_func$,\n"); +} + +void EnumFieldGenerator::GenerateCFunctionDeclarations( + io::Printer* printer) const { + if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) return; + + printer->Print( + variables_, + "int32_t $owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message);\n" + "void Set$owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message, int32_t value);\n" + "\n"); +} + +void EnumFieldGenerator::GenerateCFunctionImplementations( + io::Printer* printer) const { + if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) return; + + printer->Print( + variables_, + "int32_t $owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message) {\n" + " GPBDescriptor *descriptor = [$owning_message_class$ descriptor];\n" + " GPBFieldDescriptor *field = [descriptor fieldWithNumber:$field_number_name$];\n" + " return GPBGetInt32IvarWithField(message, field);\n" + "}\n" + "\n" + "void Set$owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message, int32_t value) {\n" + " GPBDescriptor *descriptor = [$owning_message_class$ descriptor];\n" + " GPBFieldDescriptor *field = [descriptor fieldWithNumber:$field_number_name$];\n" + " GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax);\n" + "}\n" + "\n"); +} + +RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator( + const FieldDescriptor* descriptor) + : RepeatedFieldGenerator(descriptor) { + SetEnumVariables(descriptor, &variables_); + variables_["array_storage_type"] = "GPBEnumArray"; +} + +RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} + +void RepeatedEnumFieldGenerator::GenerateFieldDescriptionTypeSpecific( + io::Printer* printer) const { + // TODO(thomasvl): Output the CPP check to use descFunc or validator based + // on final compile. + printer->Print( + variables_, + " .typeSpecific.enumDescFunc = $enum_desc_func$,\n"); +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h new file mode 100644 index 00000000..2d5822bb --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h @@ -0,0 +1,77 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_FIELD_H__ + +#include <map> +#include <string> +#include <google/protobuf/compiler/objectivec/objectivec_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +class EnumFieldGenerator : public SingleFieldGenerator { + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + + public: + virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const; + virtual void GenerateCFunctionDeclarations(io::Printer* printer) const; + virtual void GenerateCFunctionImplementations(io::Printer* printer) const; + + protected: + EnumFieldGenerator(const FieldDescriptor* descriptor); + virtual ~EnumFieldGenerator(); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator); +}; + +class RepeatedEnumFieldGenerator : public RepeatedFieldGenerator { + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + + public: + virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const; + + protected: + RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor); + virtual ~RepeatedEnumFieldGenerator(); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator); +}; + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_FIELD_H__ diff --git a/src/google/protobuf/compiler/objectivec/objectivec_extension.cc b/src/google/protobuf/compiler/objectivec/objectivec_extension.cc new file mode 100644 index 00000000..b19c1b45 --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_extension.cc @@ -0,0 +1,166 @@ +// 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. + +#include <iostream> + +#include <google/protobuf/compiler/objectivec/objectivec_extension.h> +#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/io/printer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +ExtensionGenerator::ExtensionGenerator(const string& root_class_name, + const FieldDescriptor* descriptor) + : method_name_(ExtensionMethodName(descriptor)), + root_class_and_method_name_(root_class_name + "_" + method_name_), + descriptor_(descriptor) { + // Extensions can be filtered via the method they are accessed off the + // file's Root with. + if (FilterClass(root_class_and_method_name_)) { + filter_reason_ = + string("Extension |") + root_class_and_method_name_ + "| was not whitelisted."; + } else { + // Extensions that add a Message field also require that field be allowed + // by the filter, or they aren't usable. + ObjectiveCType objc_type = GetObjectiveCType(descriptor_); + if (objc_type == OBJECTIVECTYPE_MESSAGE) { + const string message_class_name(ClassName(descriptor_->message_type())); + if (FilterClass(message_class_name)) { + filter_reason_ = string("Extension |") + root_class_and_method_name_ + + "| needs message |" + message_class_name + + "|, which was not whitelisted."; + } + } + } + if (descriptor->is_map()) { + // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some + // error case, so it seem to be ok to use as a back door for errors. + cerr << "error: Extension is a map<>!" + << " That used to be blocked by the compiler." << endl; + cerr.flush(); + abort(); + } +} + +ExtensionGenerator::~ExtensionGenerator() {} + +void ExtensionGenerator::GenerateMembersHeader(io::Printer* printer) { + WriteClassNameToClassList(root_class_and_method_name_); + if (IsFiltered()) { + printer->Print("// $filter_reason$\n\n", "filter_reason", filter_reason_); + return; + } + map<string, string> vars; + vars["method_name"] = method_name_; + SourceLocation location; + if (descriptor_->GetSourceLocation(&location)) { + vars["comments"] = BuildCommentsString(location); + } else { + vars["comments"] = ""; + } + printer->Print(vars, + "$comments$" + "+ (GPBExtensionField*)$method_name$;\n"); +} + +void ExtensionGenerator::GenerateStaticVariablesInitialization( + io::Printer* printer, bool* out_generated, bool root) { + if (IsFiltered()) { + return; + } + *out_generated = true; + map<string, string> vars; + vars["root_class_and_method_name"] = root_class_and_method_name_; + vars["extended_type"] = ClassName(descriptor_->containing_type()); + vars["number"] = SimpleItoa(descriptor_->number()); + + std::vector<string> options; + if (descriptor_->is_repeated()) options.push_back("GPBExtensionRepeated"); + if (descriptor_->options().packed()) options.push_back("GPBExtensionPacked"); + if (descriptor_->containing_type()->options().message_set_wire_format()) + options.push_back("GPBExtensionSetWireFormat"); + + vars["options"] = BuildFlagsString(options); + + ObjectiveCType objc_type = GetObjectiveCType(descriptor_); + string singular_type; + if (objc_type == OBJECTIVECTYPE_MESSAGE) { + vars["type"] = string("GPBStringifySymbol(") + + ClassName(descriptor_->message_type()) + ")"; + } else { + vars["type"] = "NULL"; + } + + vars["default_name"] = GPBValueFieldName(descriptor_); + if (descriptor_->is_repeated()) { + vars["default"] = "nil"; + } else { + vars["default"] = DefaultValue(descriptor_); + } + string type = GetCapitalizedType(descriptor_); + vars["extension_type"] = string("GPBType") + type; + + if (objc_type == OBJECTIVECTYPE_ENUM) { + vars["enum_desc_func_name"] = + EnumName(descriptor_->enum_type()) + "_EnumDescriptor"; + } else { + vars["enum_desc_func_name"] = "NULL"; + } + + printer->Print(vars, + "{\n" + " .singletonName = GPBStringifySymbol($root_class_and_method_name$),\n" + " .type = $extension_type$,\n" + " .extendedClass = GPBStringifySymbol($extended_type$),\n" + " .fieldNumber = $number$,\n" + " .defaultValue.$default_name$ = $default$,\n" + " .messageOrGroupClassName = $type$,\n" + " .options = $options$,\n" + " .enumDescriptorFunc = $enum_desc_func_name$,\n" + "},\n"); +} + +void ExtensionGenerator::GenerateRegistrationSource(io::Printer* printer) { + if (IsFiltered()) { + return; + } + printer->Print( + "[registry addExtension:$root_class_and_method_name$];\n", + "root_class_and_method_name", root_class_and_method_name_); +} +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/objectivec/objectivec_extension.h b/src/google/protobuf/compiler/objectivec/objectivec_extension.h new file mode 100644 index 00000000..d17f5be9 --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_extension.h @@ -0,0 +1,73 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_EXTENSION_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_EXTENSION_H__ + +#include <google/protobuf/stubs/common.h> + +namespace google { +namespace protobuf { +class FieldDescriptor; // descriptor.h +namespace io { +class Printer; // printer.h +} +} + +namespace protobuf { +namespace compiler { +namespace objectivec { + +class ExtensionGenerator { + public: + explicit ExtensionGenerator(const string& root_class_name, + const FieldDescriptor* descriptor); + ~ExtensionGenerator(); + + void GenerateMembersHeader(io::Printer* printer); + void GenerateStaticVariablesInitialization(io::Printer* printer, + bool* out_generated, bool root); + void GenerateRegistrationSource(io::Printer* printer); + + bool IsFiltered() const { return filter_reason_.length() > 0; } + + private: + string method_name_; + string root_class_and_method_name_; + string filter_reason_; + const FieldDescriptor* descriptor_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator); +}; +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_H__ diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_field.cc new file mode 100644 index 00000000..b071ce5d --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_field.cc @@ -0,0 +1,474 @@ +// 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. + +#include <google/protobuf/compiler/objectivec/objectivec_field.h> +#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> +#include <google/protobuf/compiler/objectivec/objectivec_enum_field.h> +#include <google/protobuf/compiler/objectivec/objectivec_map_field.h> +#include <google/protobuf/compiler/objectivec/objectivec_message_field.h> +#include <google/protobuf/compiler/objectivec/objectivec_primitive_field.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/wire_format.h> +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/strutil.h> + +#ifndef htonl +#include <netinet/in.h> +#endif + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +namespace { +void SetCommonFieldVariables(const FieldDescriptor* descriptor, + map<string, string>* variables) { + string camel_case_name = FieldName(descriptor); + string raw_field_name; + if (descriptor->type() == FieldDescriptor::TYPE_GROUP) { + raw_field_name = descriptor->message_type()->name(); + } else { + raw_field_name = descriptor->name(); + } + // The logic here has to match -[GGPBFieldDescriptor textFormatName]. + const string un_camel_case_name( + UnCamelCaseFieldName(camel_case_name, descriptor)); + const bool needs_custom_name = (raw_field_name != un_camel_case_name); + + SourceLocation location; + if (descriptor->GetSourceLocation(&location)) { + (*variables)["comments"] = BuildCommentsString(location); + } else { + (*variables)["comments"] = "\n"; + } + const string& classname = ClassName(descriptor->containing_type()); + (*variables)["classname"] = classname; + (*variables)["name"] = camel_case_name; + const string& capitalized_name = FieldNameCapitalized(descriptor); + (*variables)["capitalized_name"] = capitalized_name; + (*variables)["raw_field_name"] = raw_field_name; + (*variables)["field_number_name"] = + classname + "_FieldNumber_" + capitalized_name; + (*variables)["field_number"] = SimpleItoa(descriptor->number()); + (*variables)["has_index"] = SimpleItoa(descriptor->index()); + (*variables)["field_type"] = GetCapitalizedType(descriptor); + std::vector<string> field_flags; + if (descriptor->is_repeated()) field_flags.push_back("GPBFieldRepeated"); + if (descriptor->is_required()) field_flags.push_back("GPBFieldRequired"); + if (descriptor->is_optional()) field_flags.push_back("GPBFieldOptional"); + if (descriptor->options().packed()) field_flags.push_back("GPBFieldPacked"); + + // ObjC custom flags. + if (descriptor->has_default_value()) + field_flags.push_back("GPBFieldHasDefaultValue"); + if (needs_custom_name) field_flags.push_back("GPBFieldTextFormatNameCustom"); + if (descriptor->type() == FieldDescriptor::TYPE_ENUM) { + // TODO(thomasvl): Output the CPP check to use descFunc or validator based + // on final compile. + field_flags.push_back("GPBFieldHasEnumDescriptor"); + } + + (*variables)["fieldflags"] = BuildFlagsString(field_flags); + + (*variables)["default"] = DefaultValue(descriptor); + (*variables)["default_name"] = GPBValueFieldName(descriptor); + + (*variables)["typeSpecific_name"] = "className"; + (*variables)["typeSpecific_value"] = "NULL"; + + string field_options = descriptor->options().SerializeAsString(); + // Must convert to a standard byte order for packing length into + // a cstring. + uint32_t length = htonl(field_options.length()); + if (length > 0) { + string bytes((const char*)&length, sizeof(length)); + bytes.append(field_options); + string options_str = "\"" + CEscape(bytes) + "\""; + (*variables)["fieldoptions"] = "\"" + CEscape(bytes) + "\""; + } else { + (*variables)["fieldoptions"] = ""; + } + + // Clear some common things so they can be set just when needed. + (*variables)["storage_attribute"] = ""; +} + +// A field generator that writes nothing. +class EmptyFieldGenerator : public FieldGenerator { + public: + EmptyFieldGenerator(const FieldDescriptor* descriptor, const string& reason) + : FieldGenerator(descriptor), reason_(reason) {} + virtual ~EmptyFieldGenerator() {} + + virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const {} + virtual void GeneratePropertyDeclaration(io::Printer* printer) const { + string name = FieldName(descriptor_); + string type; + switch (GetObjectiveCType(descriptor_)) { + case OBJECTIVECTYPE_MESSAGE: + type = ClassName(descriptor_->message_type()) + " *"; + break; + + case OBJECTIVECTYPE_ENUM: + type = EnumName(descriptor_->enum_type()) + " "; + break; + + default: + type = string(descriptor_->type_name()) + " "; + break; + } + printer->Print("// Field |$type$$name$| $reason$\n\n", "type", type, "name", + name, "reason", reason_); + } + + virtual void GenerateFieldNumberConstant(io::Printer* printer) const {} + virtual void GeneratePropertyImplementation(io::Printer* printer) const {} + virtual void GenerateFieldDescription(io::Printer* printer) const {} + + virtual bool WantsHasProperty(void) const { return false; } + + private: + string reason_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EmptyFieldGenerator); +}; + +} // namespace + +FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field) { + FieldGenerator* result = NULL; + if (field->is_repeated()) { + switch (GetObjectiveCType(field)) { + case OBJECTIVECTYPE_MESSAGE: { + string type = ClassName(field->message_type()); + if (FilterClass(type)) { + string reason = + "Filtered by |" + type + "| not being whitelisted."; + result = new EmptyFieldGenerator(field, reason); + } else if (field->is_map()) { + result = new MapFieldGenerator(field); + } else { + result = new RepeatedMessageFieldGenerator(field); + } + break; + } + case OBJECTIVECTYPE_ENUM: + result = new RepeatedEnumFieldGenerator(field); + break; + default: + result = new RepeatedPrimitiveFieldGenerator(field); + break; + } + } else { + switch (GetObjectiveCType(field)) { + case OBJECTIVECTYPE_MESSAGE: { + string type = ClassName(field->message_type()); + if (FilterClass(type)) { + string reason = + "Filtered by |" + type + "| not being whitelisted."; + result = new EmptyFieldGenerator(field, reason); + } else { + result = new MessageFieldGenerator(field); + } + break; + } + case OBJECTIVECTYPE_ENUM: + result = new EnumFieldGenerator(field); + break; + default: + if (IsReferenceType(field)) { + result = new PrimitiveObjFieldGenerator(field); + } else { + result = new PrimitiveFieldGenerator(field); + } + break; + } + } + result->FinishInitialization(); + return result; +} + + +FieldGenerator::FieldGenerator(const FieldDescriptor* descriptor) + : descriptor_(descriptor) { + SetCommonFieldVariables(descriptor, &variables_); +} + +FieldGenerator::~FieldGenerator() {} + +void FieldGenerator::GenerateFieldNumberConstant(io::Printer* printer) const { + printer->Print( + variables_, + "$field_number_name$ = $field_number$,\n"); +} + +void FieldGenerator::GenerateCFunctionDeclarations( + io::Printer* printer) const { + // Nothing +} + +void FieldGenerator::GenerateCFunctionImplementations( + io::Printer* printer) const { + // Nothing +} + +void FieldGenerator::GenerateFieldDescription( + io::Printer* printer) const { + printer->Print( + variables_, + "{\n" + " .name = \"$name$\",\n" + " .number = $field_number_name$,\n" + " .hasIndex = $has_index$,\n" + " .flags = $fieldflags$,\n" + " .type = GPBType$field_type$,\n" + " .offset = offsetof($classname$_Storage, $name$),\n" + " .defaultValue.$default_name$ = $default$,\n"); + + // " .typeSpecific.value* = [something]," + GenerateFieldDescriptionTypeSpecific(printer); + + const string& field_options(variables_.at("fieldoptions")); + if (field_options.empty()) { + printer->Print(" .fieldOptions = NULL,\n"); + } else { + // Can't use PrintRaw() here to get the #if/#else/#endif lines completely + // outdented because the need for indent captured on the previous + // printing of a \n and there is no way to get the current indent level + // to call the right number of Outdent()/Indents() to maintain state. + printer->Print( + variables_, + "#if GPBOBJC_INCLUDE_FIELD_OPTIONS\n" + " .fieldOptions = $fieldoptions$,\n" + "#else\n" + " .fieldOptions = NULL,\n" + "#endif // GPBOBJC_INCLUDE_FIELD_OPTIONS\n"); + } + + printer->Print("},\n"); +} + +void FieldGenerator::GenerateFieldDescriptionTypeSpecific( + io::Printer* printer) const { + printer->Print( + variables_, + " .typeSpecific.$typeSpecific_name$ = $typeSpecific_value$,\n"); +} + +void FieldGenerator::SetOneofIndexBase(int index_base) { + if (descriptor_->containing_oneof() != NULL) { + int index = descriptor_->containing_oneof()->index() + index_base; + // Flip the sign to mark it as a oneof. + variables_["has_index"] = SimpleItoa(-index);; + } +} + +void FieldGenerator::FinishInitialization(void) { + // Nothing +} + +SingleFieldGenerator::SingleFieldGenerator( + const FieldDescriptor* descriptor) + : FieldGenerator(descriptor) { + // Nothing +} + +SingleFieldGenerator::~SingleFieldGenerator() {} + +void SingleFieldGenerator::GenerateFieldStorageDeclaration( + io::Printer* printer) const { + printer->Print(variables_, "$storage_type$ $name$;\n"); +} + +void SingleFieldGenerator::GeneratePropertyDeclaration( + io::Printer* printer) const { + printer->Print(variables_, "$comments$"); + if (WantsHasProperty()) { + printer->Print( + variables_, + "@property(nonatomic, readwrite) BOOL has$capitalized_name$;\n"); + } + printer->Print( + variables_, + "@property(nonatomic, readwrite) $storage_type$ $name$;\n" + "\n"); +} + +void SingleFieldGenerator::GeneratePropertyImplementation( + io::Printer* printer) const { + if (WantsHasProperty()) { + printer->Print(variables_, "@dynamic has$capitalized_name$, $name$;\n"); + } else { + printer->Print(variables_, "@dynamic $name$;\n"); + } +} + +bool SingleFieldGenerator::WantsHasProperty(void) const { + if (descriptor_->containing_oneof() != NULL) { + // If in a oneof, it uses the oneofcase instead of a has bit. + return false; + } + if (HasFieldPresence(descriptor_->file())) { + // In proto1/proto2, every field has a has_$name$() method. + return true; + } + return false; +} + +ObjCObjFieldGenerator::ObjCObjFieldGenerator( + const FieldDescriptor* descriptor) + : SingleFieldGenerator(descriptor) { + variables_["property_storage_attribute"] = "strong"; + if (IsRetainedName(variables_["name"])) { + variables_["storage_attribute"] = " NS_RETURNS_NOT_RETAINED"; + } +} + +ObjCObjFieldGenerator::~ObjCObjFieldGenerator() {} + +void ObjCObjFieldGenerator::GenerateFieldStorageDeclaration( + io::Printer* printer) const { + printer->Print(variables_, "$storage_type$ *$name$;\n"); +} + +void ObjCObjFieldGenerator::GeneratePropertyDeclaration( + io::Printer* printer) const { + + // Differs from SingleFieldGenerator::GeneratePropertyDeclaration() in that + // it uses pointers and deals with Objective C's rules around storage name + // conventions (init*, new*, etc.) + + printer->Print(variables_, "$comments$"); + if (WantsHasProperty()) { + printer->Print( + variables_, + "@property(nonatomic, readwrite) BOOL has$capitalized_name$;\n"); + } + printer->Print( + variables_, + "@property(nonatomic, readwrite, $property_storage_attribute$) $storage_type$ *$name$$storage_attribute$;\n"); + if (IsInitName(variables_.at("name"))) { + // If property name starts with init we need to annotate it to get past ARC. + // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227 + printer->Print(variables_, + "- ($storage_type$ *)$name$ GPB_METHOD_FAMILY_NONE;\n"); + } + printer->Print("\n"); +} + +RepeatedFieldGenerator::RepeatedFieldGenerator( + const FieldDescriptor* descriptor) + : ObjCObjFieldGenerator(descriptor) { + // Repeated fields don't use the has index. + variables_["has_index"] = "GPBNoHasBit"; +} + +RepeatedFieldGenerator::~RepeatedFieldGenerator() {} + +void RepeatedFieldGenerator::FinishInitialization(void) { + FieldGenerator::FinishInitialization(); + variables_["array_comment"] = + "// |" + variables_["name"] + "| contains |" + variables_["storage_type"] + "|\n"; +} + +void RepeatedFieldGenerator::GenerateFieldStorageDeclaration( + io::Printer* printer) const { + printer->Print(variables_, "$array_storage_type$ *$name$;\n"); +} + +void RepeatedFieldGenerator::GeneratePropertyImplementation( + io::Printer* printer) const { + printer->Print(variables_, "@dynamic $name$;\n"); +} + +void RepeatedFieldGenerator::GeneratePropertyDeclaration( + io::Printer* printer) const { + + // Repeated fields don't need the has* properties, but this has the same + // logic as ObjCObjFieldGenerator::GeneratePropertyDeclaration() for dealing + // with needing Objective C's rules around storage name conventions (init*, + // new*, etc.) + + printer->Print( + variables_, + "$comments$" + "$array_comment$" + "@property(nonatomic, readwrite, strong) $array_storage_type$ *$name$$storage_attribute$;\n"); + if (IsInitName(variables_.at("name"))) { + // If property name starts with init we need to annotate it to get past ARC. + // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227 + printer->Print(variables_, + "- ($array_storage_type$ *)$name$ GPB_METHOD_FAMILY_NONE;\n"); + } + printer->Print("\n"); +} + +bool RepeatedFieldGenerator::WantsHasProperty(void) const { + // Consumer check the array size/existance rather than a has bit. + return false; +} + +FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor) + : descriptor_(descriptor), + field_generators_( + new scoped_ptr<FieldGenerator>[descriptor->field_count()]), + extension_generators_( + new scoped_ptr<FieldGenerator>[descriptor->extension_count()]) { + // Construct all the FieldGenerators. + for (int i = 0; i < descriptor->field_count(); i++) { + field_generators_[i].reset(FieldGenerator::Make(descriptor->field(i))); + } + for (int i = 0; i < descriptor->extension_count(); i++) { + extension_generators_[i].reset(FieldGenerator::Make(descriptor->extension(i))); + } +} + +FieldGeneratorMap::~FieldGeneratorMap() {} + +const FieldGenerator& FieldGeneratorMap::get( + const FieldDescriptor* field) const { + GOOGLE_CHECK_EQ(field->containing_type(), descriptor_); + return *field_generators_[field->index()]; +} + +const FieldGenerator& FieldGeneratorMap::get_extension(int index) const { + return *extension_generators_[index]; +} + +void FieldGeneratorMap::SetOneofIndexBase(int index_base) { + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_[i]->SetOneofIndexBase(index_base); + } +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.h b/src/google/protobuf/compiler/objectivec/objectivec_field.h new file mode 100644 index 00000000..c65e73b2 --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_field.h @@ -0,0 +1,166 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FIELD_H__ + +#include <map> +#include <string> +#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/descriptor.h> + +namespace google { +namespace protobuf { + +namespace io { +class Printer; // printer.h +} // namespace io + +namespace compiler { +namespace objectivec { + +class FieldGenerator { + public: + static FieldGenerator* Make(const FieldDescriptor* field); + + virtual ~FieldGenerator(); + + virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const = 0; + virtual void GeneratePropertyDeclaration(io::Printer* printer) const = 0; + + virtual void GeneratePropertyImplementation(io::Printer* printer) const = 0; + + virtual void GenerateFieldDescription(io::Printer* printer) const; + virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const; + virtual void GenerateFieldNumberConstant(io::Printer* printer) const; + + virtual void GenerateCFunctionDeclarations(io::Printer* printer) const; + virtual void GenerateCFunctionImplementations(io::Printer* printer) const; + + void SetOneofIndexBase(int index_base); + + string variable(const char* key) const { + return variables_.find(key)->second; + } + + bool needs_textformat_name_support() const { + const string& field_flags = variable("fieldflags"); + return field_flags.find("GPBFieldTextFormatNameCustom") != string::npos; + } + string generated_objc_name() const { return variable("name"); } + string raw_field_name() const { return variable("raw_field_name"); } + + protected: + FieldGenerator(const FieldDescriptor* descriptor); + + virtual void FinishInitialization(void); + virtual bool WantsHasProperty(void) const = 0; + + const FieldDescriptor* descriptor_; + map<string, string> variables_; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator); +}; + +class SingleFieldGenerator : public FieldGenerator { + public: + virtual ~SingleFieldGenerator(); + + virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const; + virtual void GeneratePropertyDeclaration(io::Printer* printer) const; + + virtual void GeneratePropertyImplementation(io::Printer* printer) const; + + protected: + SingleFieldGenerator(const FieldDescriptor* descriptor); + virtual bool WantsHasProperty(void) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SingleFieldGenerator); +}; + +// Subclass with common support for when the field ends up as an ObjC Object. +class ObjCObjFieldGenerator : public SingleFieldGenerator { + public: + virtual ~ObjCObjFieldGenerator(); + + virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const; + virtual void GeneratePropertyDeclaration(io::Printer* printer) const; + + protected: + ObjCObjFieldGenerator(const FieldDescriptor* descriptor); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjCObjFieldGenerator); +}; + +class RepeatedFieldGenerator : public ObjCObjFieldGenerator { + public: + virtual ~RepeatedFieldGenerator(); + + virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const; + virtual void GeneratePropertyDeclaration(io::Printer* printer) const; + + virtual void GeneratePropertyImplementation(io::Printer* printer) const; + + protected: + RepeatedFieldGenerator(const FieldDescriptor* descriptor); + virtual void FinishInitialization(void); + virtual bool WantsHasProperty(void) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedFieldGenerator); +}; + +// Convenience class which constructs FieldGenerators for a Descriptor. +class FieldGeneratorMap { + public: + FieldGeneratorMap(const Descriptor* descriptor); + ~FieldGeneratorMap(); + + const FieldGenerator& get(const FieldDescriptor* field) const; + const FieldGenerator& get_extension(int index) const; + + void SetOneofIndexBase(int index_base); + + private: + const Descriptor* descriptor_; + scoped_array<scoped_ptr<FieldGenerator> > field_generators_; + scoped_array<scoped_ptr<FieldGenerator> > extension_generators_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap); +}; +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FIELD_H__ diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.cc b/src/google/protobuf/compiler/objectivec/objectivec_file.cc new file mode 100644 index 00000000..f1e8c0a0 --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc @@ -0,0 +1,392 @@ +// 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. + +#include <google/protobuf/compiler/objectivec/objectivec_file.h> +#include <google/protobuf/compiler/objectivec/objectivec_enum.h> +#include <google/protobuf/compiler/objectivec/objectivec_extension.h> +#include <google/protobuf/compiler/objectivec/objectivec_message.h> +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream_impl.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/stubs/stl_util.h> +#include <google/protobuf/stubs/strutil.h> +#include <sstream> + +// This is also found in GPBBootstrap.h, and needs to be kept in sync. It +// is the version check done to ensure generated code works with the current +// runtime being used. +const int32_t GOOGLE_PROTOBUF_OBJC_GEN_VERSION = 30000; + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { +FileGenerator::FileGenerator(const FileDescriptor *file) + : file_(file), + root_class_name_(FileClassName(file)), + is_filtered_(true), + all_extensions_filtered_(true) { + for (int i = 0; i < file_->enum_type_count(); i++) { + EnumGenerator *generator = new EnumGenerator(file_->enum_type(i)); + // The enums are exposed via C functions, so they will dead strip if + // not used. + is_filtered_ &= false; + enum_generators_.push_back(generator); + } + for (int i = 0; i < file_->message_type_count(); i++) { + MessageGenerator *generator = + new MessageGenerator(root_class_name_, file_->message_type(i)); + is_filtered_ &= generator->IsFiltered(); + is_filtered_ &= generator->IsSubContentFiltered(); + message_generators_.push_back(generator); + } + for (int i = 0; i < file_->extension_count(); i++) { + ExtensionGenerator *generator = + new ExtensionGenerator(root_class_name_, file_->extension(i)); + is_filtered_ &= generator->IsFiltered(); + all_extensions_filtered_ &= generator->IsFiltered(); + extension_generators_.push_back(generator); + } + // If there is nothing in the file we filter it. +} + +FileGenerator::~FileGenerator() { + STLDeleteContainerPointers(dependency_generators_.begin(), + dependency_generators_.end()); + STLDeleteContainerPointers(enum_generators_.begin(), enum_generators_.end()); + STLDeleteContainerPointers(message_generators_.begin(), + message_generators_.end()); + STLDeleteContainerPointers(extension_generators_.begin(), + extension_generators_.end()); +} + +void FileGenerator::GenerateHeader(io::Printer *printer) { + printer->Print( + "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "// source: $filename$\n" + "\n", + "filename", file_->name()); + + printer->Print("#import \"GPBProtocolBuffers.h\"\n\n"); + + // Add some verification that the generated code matches the source the + // code is being compiled with. + printer->Print( + "#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != $protoc_gen_objc_version$\n" + "#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.\n" + "#endif\n" + "\n", + "protoc_gen_objc_version", + SimpleItoa(GOOGLE_PROTOBUF_OBJC_GEN_VERSION)); + + if (!IsFiltered()) { + const vector<FileGenerator *> &dependency_generators = + DependencyGenerators(); + if (dependency_generators.size() > 0) { + for (vector<FileGenerator *>::const_iterator iter = + dependency_generators.begin(); + iter != dependency_generators.end(); ++iter) { + printer->Print("#import \"$header$.pbobjc.h\"\n", + "header", (*iter)->Path()); + } + printer->Print("\n"); + } + } + + printer->Print("CF_EXTERN_C_BEGIN\n\n"); + + if (!IsFiltered()) { + set<string> dependencies; + DetermineDependencies(&dependencies); + for (set<string>::const_iterator i(dependencies.begin()); + i != dependencies.end(); ++i) { + printer->Print("$value$;\n", "value", *i); + } + + if (dependencies.begin() != dependencies.end()) { + printer->Print("\n"); + } + } + + // need to write out all enums first + for (vector<EnumGenerator *>::iterator iter = enum_generators_.begin(); + iter != enum_generators_.end(); ++iter) { + (*iter)->GenerateHeader(printer); + } + + for (vector<MessageGenerator *>::iterator iter = message_generators_.begin(); + iter != message_generators_.end(); ++iter) { + (*iter)->GenerateEnumHeader(printer); + } + + // For extensions to chain together, the Root gets created even if there + // are no extensions. So if the entire file isn't filtered away, output it. + if (!IsFiltered()) { + printer->Print( + "\n" + "#pragma mark - $root_class_name$\n" + "\n" + "@interface $root_class_name$ : GPBRootObject\n" + "@end\n\n", + "root_class_name", root_class_name_); + } + + if (extension_generators_.size() > 0) { + // The dynamic methods block is only needed if there are extensions. If + // they are all filtered, output the @interface as a comment so there is + // something left in the header for anyone that looks. + const char *root_line_prefix = ""; + if (AreAllExtensionsFiltered()) { + root_line_prefix = "// "; + } + printer->Print( + "$root_line_prefix$@interface $root_class_name$ (DynamicMethods)\n", + "root_class_name", root_class_name_, + "root_line_prefix", root_line_prefix); + + for (vector<ExtensionGenerator *>::iterator iter = + extension_generators_.begin(); + iter != extension_generators_.end(); ++iter) { + (*iter)->GenerateMembersHeader(printer); + } + + printer->Print("$root_line_prefix$@end\n\n", + "root_line_prefix", root_line_prefix); + } // extension_generators_.size() > 0 + + for (vector<MessageGenerator *>::iterator iter = message_generators_.begin(); + iter != message_generators_.end(); ++iter) { + (*iter)->GenerateMessageHeader(printer); + } + + printer->Print("CF_EXTERN_C_END\n"); +} + +void DetermineDependenciesWorker(set<string> *dependencies, + set<string> *seen_files, + const string &classname, + const FileDescriptor *file) { + if (seen_files->find(file->name()) != seen_files->end()) { + // don't infinitely recurse + return; + } + + seen_files->insert(file->name()); + + for (int i = 0; i < file->dependency_count(); i++) { + DetermineDependenciesWorker(dependencies, seen_files, classname, + file->dependency(i)); + } + for (int i = 0; i < file->message_type_count(); i++) { + MessageGenerator(classname, file->message_type(i)) + .DetermineDependencies(dependencies); + } +} + +void FileGenerator::DetermineDependencies(set<string> *dependencies) { + set<string> seen_files; + DetermineDependenciesWorker(dependencies, &seen_files, root_class_name_, + file_); +} + +void FileGenerator::GenerateSource(io::Printer *printer) { + printer->Print( + "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "// source: $filename$\n" + "\n", + "filename", file_->name()); + + if (IsFiltered()) { + printer->Print( + "// File empty because all messages, extensions and enum have been filtered.\n" + "\n" + "\n" + "// Dummy symbol that will be stripped but will avoid linker warnings about\n" + "// no symbols in the .o form compiling this file.\n" + "static int $root_class_name$_dummy __attribute__((unused,used)) = 0;\n", + "root_class_name", root_class_name_); + return; + } + + printer->Print("#import \"GPBProtocolBuffers_RuntimeSupport.h\"\n\n"); + + string header_file = Path() + ".pbobjc.h"; + + printer->Print( + "#import \"$header_file$\"\n" + "\n" + "#pragma mark - $root_class_name$\n" + "\n" + "@implementation $root_class_name$\n\n", + "header_file", header_file, + "root_class_name", root_class_name_); + + bool generated_extensions = false; + if (file_->extension_count() + file_->message_type_count() + + file_->dependency_count() > + 0) { + ostringstream extensions_stringstream; + + if (file_->extension_count() + file_->message_type_count() > 0) { + io::OstreamOutputStream extensions_outputstream(&extensions_stringstream); + io::Printer extensions_printer(&extensions_outputstream, '$'); + extensions_printer.Print( + "static GPBExtensionDescription descriptions[] = {\n"); + extensions_printer.Indent(); + for (vector<ExtensionGenerator *>::iterator iter = + extension_generators_.begin(); + iter != extension_generators_.end(); ++iter) { + (*iter)->GenerateStaticVariablesInitialization( + &extensions_printer, &generated_extensions, true); + } + for (vector<MessageGenerator *>::iterator iter = + message_generators_.begin(); + iter != message_generators_.end(); ++iter) { + (*iter)->GenerateStaticVariablesInitialization(&extensions_printer, + &generated_extensions); + } + extensions_printer.Outdent(); + extensions_printer.Print("};\n"); + if (generated_extensions) { + extensions_printer.Print( + "for (size_t i = 0; i < sizeof(descriptions) / sizeof(descriptions[0]); ++i) {\n" + " GPBExtensionField *extension = [[GPBExtensionField alloc] initWithDescription:&descriptions[i]];\n" + " [registry addExtension:extension];\n" + " [self globallyRegisterExtension:extension];\n" + " [extension release];\n" + "}\n"); + } else { + extensions_printer.Print("#pragma unused (descriptions)\n"); + } + const vector<FileGenerator *> &dependency_generators = + DependencyGenerators(); + if (dependency_generators.size()) { + for (vector<FileGenerator *>::const_iterator iter = + dependency_generators.begin(); + iter != dependency_generators.end(); ++iter) { + if (!(*iter)->IsFiltered()) { + extensions_printer.Print( + "[registry addExtensions:[$dependency$ extensionRegistry]];\n", + "dependency", (*iter)->RootClassName()); + generated_extensions = true; + } + } + } else if (!generated_extensions) { + extensions_printer.Print("#pragma unused (registry)\n"); + } + } + + if (generated_extensions) { + printer->Print( + "+ (GPBExtensionRegistry*)extensionRegistry {\n" + " // This is called by +initialize so there is no need to worry\n" + " // about thread safety and initialization of registry.\n" + " static GPBExtensionRegistry* registry = nil;\n" + " if (!registry) {\n" + " registry = [[GPBExtensionRegistry alloc] init];\n"); + + printer->Indent(); + printer->Indent(); + + extensions_stringstream.flush(); + printer->Print(extensions_stringstream.str().c_str()); + printer->Outdent(); + printer->Outdent(); + + printer->Print( + " }\n" + " return registry;\n" + "}\n" + "\n" + "+ (void)load {\n" + " @autoreleasepool {\n" + " [self extensionRegistry]; // Construct extension registry.\n" + " }\n" + "}\n\n"); + } + } + + printer->Print("@end\n\n"); + + + string syntax; + switch (file_->syntax()) { + case FileDescriptor::SYNTAX_UNKNOWN: + syntax = "GPBFileSyntaxUnknown"; + break; + case FileDescriptor::SYNTAX_PROTO2: + syntax = "GPBFileSyntaxProto2"; + break; + case FileDescriptor::SYNTAX_PROTO3: + syntax = "GPBFileSyntaxProto3"; + break; + } + printer->Print( + "static GPBFileDescriptor *$root_class_name$_FileDescriptor(void) {\n" + " // This is called by +initialize so there is no need to worry\n" + " // about thread safety of the singleton.\n" + " static GPBFileDescriptor *descriptor = NULL;\n" + " if (!descriptor) {\n" + " descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n" + " syntax:$syntax$];\n" + " }\n" + " return descriptor;\n" + "}\n" + "\n", + "root_class_name", root_class_name_, + "package", file_->package(), + "syntax", syntax); + + for (vector<EnumGenerator *>::iterator iter = enum_generators_.begin(); + iter != enum_generators_.end(); ++iter) { + (*iter)->GenerateSource(printer); + } + for (vector<MessageGenerator *>::iterator iter = message_generators_.begin(); + iter != message_generators_.end(); ++iter) { + (*iter)->GenerateSource(printer); + } +} + +const string FileGenerator::Path() const { return FilePath(file_); } + +const vector<FileGenerator *> &FileGenerator::DependencyGenerators() { + if (file_->dependency_count() != dependency_generators_.size()) { + for (int i = 0; i < file_->dependency_count(); i++) { + FileGenerator *generator = new FileGenerator(file_->dependency(i)); + dependency_generators_.push_back(generator); + } + } + return dependency_generators_; +} +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.h b/src/google/protobuf/compiler/objectivec/objectivec_file.h new file mode 100644 index 00000000..fbd08eae --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_file.h @@ -0,0 +1,94 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FILE_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FILE_H__ + +#include <string> +#include <set> +#include <vector> +#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> +#include <google/protobuf/stubs/common.h> + +namespace google { +namespace protobuf { +class FileDescriptor; // descriptor.h +namespace io { +class Printer; // printer.h +} +} + +namespace protobuf { +namespace compiler { +namespace objectivec { + +class EnumGenerator; +class ExtensionGenerator; +class MessageGenerator; + +class FileGenerator { + public: + explicit FileGenerator(const FileDescriptor* file); + ~FileGenerator(); + + void GenerateSource(io::Printer* printer); + void GenerateHeader(io::Printer* printer); + + const string& RootClassName() const { return root_class_name_; } + const string Path() const; + + bool IsFiltered() const { return is_filtered_; } + bool AreAllExtensionsFiltered() const { return all_extensions_filtered_; } + + private: + const FileDescriptor* file_; + string root_class_name_; + + // Access this field through the DependencyGenerators accessor call below. + // Do not reference it directly. + vector<FileGenerator*> dependency_generators_; + + vector<EnumGenerator*> enum_generators_; + vector<MessageGenerator*> message_generators_; + vector<ExtensionGenerator*> extension_generators_; + bool is_filtered_; + bool all_extensions_filtered_; + + void DetermineDependencies(set<string>* dependencies); + + const vector<FileGenerator*>& DependencyGenerators(); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator); +}; +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FILE_H__ diff --git a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc new file mode 100644 index 00000000..1eb31a79 --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc @@ -0,0 +1,95 @@ +// 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. + +#include <iostream> +#include <google/protobuf/compiler/objectivec/objectivec_generator.h> +#include <google/protobuf/compiler/objectivec/objectivec_file.h> +#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +ObjectiveCGenerator::ObjectiveCGenerator() {} + +ObjectiveCGenerator::~ObjectiveCGenerator() {} + +bool ObjectiveCGenerator::Generate(const FileDescriptor* file, + const string& parameter, + OutputDirectory* output_directory, + string* error) const { + // ObjC doesn't have any options at the moment, error if passed one. + vector<pair<string, string> > options; + ParseGeneratorParameter(parameter, &options); + for (int i = 0; i < options.size(); i++) { + *error = "error:: Unknown generator option: " + options[i].first; + return false; + } + + if (!InitializeClassWhitelist(error)) { + return false; + } + + FileGenerator file_generator(file); + + string filepath = FilePath(file); + + // Generate header. + { + scoped_ptr<io::ZeroCopyOutputStream> output( + output_directory->Open(filepath + ".pbobjc.h")); + io::Printer printer(output.get(), '$'); + file_generator.GenerateHeader(&printer); + } + + // Generate m file. + { + scoped_ptr<io::ZeroCopyOutputStream> output( + output_directory->Open(filepath + ".pbobjc.m")); + io::Printer printer(output.get(), '$'); + file_generator.GenerateSource(&printer); + } + + if (!WriteClassList(error)) { + return false; + } + + return true; +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/objectivec/objectivec_generator.h b/src/google/protobuf/compiler/objectivec/objectivec_generator.h new file mode 100644 index 00000000..24286ac9 --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.h @@ -0,0 +1,60 @@ +// 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. + +// Generates ObjectiveC code for a given .proto file. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_GENERATOR_H__ + +#include <string> +#include <google/protobuf/compiler/code_generator.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +class LIBPROTOC_EXPORT ObjectiveCGenerator : public CodeGenerator { + public: + ObjectiveCGenerator(); + ~ObjectiveCGenerator(); + + // implements CodeGenerator ---------------------------------------- + bool Generate(const FileDescriptor* file, const string& parameter, + OutputDirectory* output_directory, string* error) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjectiveCGenerator); +}; +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_GENERATOR_H__ diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc new file mode 100644 index 00000000..a4eba09b --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc @@ -0,0 +1,1131 @@ +// 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. + +#include <arpa/inet.h> +#include <errno.h> +#include <limits.h> +#include <stdlib.h> +#include <unistd.h> + +#include <fstream> +#include <iostream> +#include <sstream> +#include <vector> + +#include <google/protobuf/stubs/hash.h> +#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> +#include <google/protobuf/io/coded_stream.h> +#include <google/protobuf/io/zero_copy_stream_impl.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/stubs/strutil.h> + +#ifndef htonl +#include <netinet/in.h> +#endif + +#ifndef O_EXLOCK +#include <sys/file.h> +#endif + +// NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some +// error case, so it seem to be ok to use as a back door for errors. + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +namespace { + +hash_set<string> gClassWhitelist; +stringstream gClassListStream; + +// islower()/isupper()/tolower()/toupper() change based on locale. + +bool IsLower(const char c) { + return ('a' <= c && c <= 'z'); +} + +bool IsUpper(const char c) { + return ('A' <= c && c <= 'Z'); +} + +char ToLower(char c) { + if ('A' <= c && c <= 'Z') { + c += 'a' - 'A'; + } + return c; +} + +// toupper() changes based on locale. We don't want this! +char ToUpper(char c) { + if ('a' <= c && c <= 'z') { + c += 'A' - 'a'; + } + return c; +} + +string TrimString(const string& s) { + string::size_type start = s.find_first_not_of(" \n\r\t"); + if (start == string::npos) { + return ""; + } + string::size_type end = s.find_last_not_of(" \n\r\t") + 1; + return s.substr(start, end - start); +} + +hash_set<string> MakeWordsMap(const char* const words[], size_t num_words) { + hash_set<string> result; + for (int i = 0; i < num_words; i++) { + result.insert(words[i]); + } + return result; +} + +const char* const kUpperSegmentsList[] = {"url", "http", "https"}; + +hash_set<string> kUpperSegments = + MakeWordsMap(kUpperSegmentsList, GOOGLE_ARRAYSIZE(kUpperSegmentsList)); + +// Internal helper for name handing. +// Do not expose this outside of helpers, stick to having functions for specific +// cases (ClassName(), FieldName()), so there is always consistent suffix rules. +string UnderscoresToCamelCase(const string& input, bool first_capitalized) { + vector<string> values; + string current; + + bool last_char_was_number = false; + bool last_char_was_lower = false; + bool last_char_was_upper = false; + for (int i = 0; i < input.size(); i++) { + char c = input[i]; + if (c >= '0' && c <= '9') { + if (!last_char_was_number) { + values.push_back(current); + current = ""; + } + current += c; + last_char_was_number = last_char_was_lower = last_char_was_upper = false; + last_char_was_number = true; + } else if (IsLower(c)) { + // lowercase letter can follow a lowercase or uppercase letter + if (!last_char_was_lower && !last_char_was_upper) { + values.push_back(current); + current = ""; + } + current += c; // already lower + last_char_was_number = last_char_was_lower = last_char_was_upper = false; + last_char_was_lower = true; + } else if (IsUpper(c)) { + if (!last_char_was_upper) { + values.push_back(current); + current = ""; + } + current += ToLower(c); + last_char_was_number = last_char_was_lower = last_char_was_upper = false; + last_char_was_upper = true; + } else { + last_char_was_number = last_char_was_lower = last_char_was_upper = false; + } + } + values.push_back(current); + + for (vector<string>::iterator i = values.begin(); i != values.end(); ++i) { + string value = *i; + bool all_upper = (kUpperSegments.count(value) > 0); + for (int j = 0; j < value.length(); j++) { + if (j == 0 || all_upper) { + value[j] = ToUpper(value[j]); + } else { + // Nothing, already in lower. + } + } + *i = value; + } + string result; + for (vector<string>::iterator i = values.begin(); i != values.end(); ++i) { + result += *i; + } + if ((result.length() != 0) && !first_capitalized) { + result[0] = ToLower(result[0]); + } + return result; +} + +const char* const kReservedWordList[] = { + // Objective C "keywords" that aren't in C + // From + // http://stackoverflow.com/questions/1873630/reserved-keywords-in-objective-c + "id", "_cmd", "super", "in", "out", "inout", "bycopy", "byref", "oneway", + "self", + + // C/C++ keywords (Incl C++ 0x11) + // From http://en.cppreference.com/w/cpp/keywords + "and", "and_eq", "alignas", "alignof", "asm", "auto", "bitand", "bitor", + "bool", "break", "case", "catch", "char", "char16_t", "char32_t", "class", + "compl", "const", "constexpr", "const_cast", "continue", "decltype", + "default", "delete", "double", "dynamic_cast", "else", "enum", "explicit", + "export", "extern ", "false", "float", "for", "friend", "goto", "if", + "inline", "int", "long", "mutable", "namespace", "new", "noexcept", "not", + "not_eq", "nullptr", "operator", "or", "or_eq", "private", "protected", + "public", "register", "reinterpret_cast", "return", "short", "signed", + "sizeof", "static", "static_assert", "static_cast", "struct", "switch", + "template", "this", "thread_local", "throw", "true", "try", "typedef", + "typeid", "typename", "union", "unsigned", "using", "virtual", "void", + "volatile", "wchar_t", "while", "xor", "xor_eq", + + // C99 keywords + // From + // http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fkeyw.htm + "restrict", + + // Objective-C Runtime typedefs + // From <obc/runtime.h> + "Category", "Ivar", "Method", "Protocol", + + // NSObject Methods + // new is covered by C++ keywords. + "description", "debugDescription", "finalize", "hash", "dealloc", "init", + "class", "superclass", "retain", "release", "autorelease", "retainCount", + "zone", "isProxy", "copy", "mutableCopy", "classForCoder", + + // GPBMessage Methods + // Only need to add instance methods that may conflict with + // method declared in protos. The main cases are methods + // that take no arguments, or setFoo:/hasFoo: type methods. + // These are currently in the same order as in GPBMessage.h. + "unknownFields", "extensionRegistry", "isInitialized", + "data", "delimitedData", "serializedSize", + "descriptor", "extensionsCurrentlySet", "clear", "sortedExtensionsInUse", + + // MacTypes.h names + "Fixed", "Fract", "Size", "LogicalAddress", "PhysicalAddress", "ByteCount", + "ByteOffset", "Duration", "AbsoluteTime", "OptionBits", "ItemCount", + "PBVersion", "ScriptCode", "LangCode", "RegionCode", "OSType", + "ProcessSerialNumber", "Point", "Rect", "FixedPoint", "FixedRect", "Style", + "StyleParameter", "StyleField", "TimeScale", "TimeBase", "TimeRecord", +}; + +hash_set<string> kReservedWords = + MakeWordsMap(kReservedWordList, GOOGLE_ARRAYSIZE(kReservedWordList)); + +string SanitizeNameForObjC(const string& input, const string& extension) { + if (kReservedWords.count(input) > 0) { + return input + extension; + } + return input; +} + +string NameFromFieldDescriptor(const FieldDescriptor* field) { + if (field->type() == FieldDescriptor::TYPE_GROUP) { + return field->message_type()->name(); + } else { + return field->name(); + } +} + +// Escape C++ trigraphs by escaping question marks to \? +string EscapeTrigraphs(const string& to_escape) { + return StringReplace(to_escape, "?", "\\?", true); +} + +void PathSplit(const string& path, string* directory, string* basename) { + string::size_type last_slash = path.rfind('/'); + if (last_slash == string::npos) { + if (directory) { + *directory = ""; + } + if (basename) { + *basename = path; + } + } else { + if (directory) { + *directory = path.substr(0, last_slash); + } + if (basename) { + *basename = path.substr(last_slash + 1); + } + } +} + +bool IsSpecialName(const string& name, const string* special_names, + size_t count) { + for (size_t i = 0; i < count; ++i) { + size_t length = special_names[i].length(); + if (name.compare(0, length, special_names[i]) == 0) { + if (name.length() > length) { + // If name is longer than the retained_name[i] that it matches + // the next character must be not lower case (newton vs newTon vs + // new_ton). + return !IsLower(name[length]); + } else { + return true; + } + } + } + return false; +} + +} // namespace + +string StripProto(const string& filename) { + if (HasSuffixString(filename, ".protodevel")) { + return StripSuffixString(filename, ".protodevel"); + } else { + return StripSuffixString(filename, ".proto"); + } +} + +bool IsRetainedName(const string& name) { + // List of prefixes from + // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html + static const string retained_names[] = {"new", "alloc", "copy", + "mutableCopy"}; + return IsSpecialName(name, retained_names, + sizeof(retained_names) / sizeof(retained_names[0])); +} + +bool IsInitName(const string& name) { + static const string init_names[] = {"init"}; + return IsSpecialName(name, init_names, + sizeof(init_names) / sizeof(init_names[0])); +} + +string BaseFileName(const FileDescriptor* file) { + string basename; + PathSplit(file->name(), NULL, &basename); + return basename; +} + +string FileName(const FileDescriptor* file) { + string path = FilePath(file); + string basename; + PathSplit(path, NULL, &basename); + return basename; +} + +string FilePath(const FileDescriptor* file) { + string output; + string basename; + string directory; + PathSplit(file->name(), &directory, &basename); + if (directory.length() > 0) { + output = directory + "/"; + } + basename = StripProto(basename); + + // CamelCase to be more ObjC friendly. + basename = UnderscoresToCamelCase(basename, true); + + output += basename; + return output; +} + +string FileClassPrefix(const FileDescriptor* file) { + // Default is empty string, no need to check has_objc_class_prefix. + return file->options().objc_class_prefix(); +} + +string FileClassName(const FileDescriptor* file) { + string name = FileClassPrefix(file); + name += UnderscoresToCamelCase(StripProto(BaseFileName(file)), true); + name += "Root"; + // There aren't really any reserved words that end in "Root", but playing + // it safe and checking. + return SanitizeNameForObjC(name, "_RootClass"); +} + +string ClassNameWorker(const Descriptor* descriptor) { + string name; + if (descriptor->containing_type() != NULL) { + name = ClassNameWorker(descriptor->containing_type()); + name += "_"; + } + return name + descriptor->name(); +} + +string ClassNameWorker(const EnumDescriptor* descriptor) { + string name; + if (descriptor->containing_type() != NULL) { + name = ClassNameWorker(descriptor->containing_type()); + name += "_"; + } + return name + descriptor->name(); +} + +string ClassName(const Descriptor* descriptor) { + // 1. Message names are used as is (style calls for CamelCase, trust it). + // 2. Check for reserved word at the very end and then suffix things. + string prefix = FileClassPrefix(descriptor->file()); + string name = ClassNameWorker(descriptor); + return SanitizeNameForObjC(prefix + name, "_Class"); +} + +string EnumName(const EnumDescriptor* descriptor) { + // 1. Enum names are used as is (style calls for CamelCase, trust it). + // 2. Check for reserved word at the every end and then suffix things. + // message Fixed { + // message Size {...} + // enum Mumble {...} + // ... + // } + // yields Fixed_Class, Fixed_Size. + string name = FileClassPrefix(descriptor->file()); + name += ClassNameWorker(descriptor); + return SanitizeNameForObjC(name, "_Enum"); +} + +string EnumValueName(const EnumValueDescriptor* descriptor) { + // Because of the Switch enum compatibility, the name on the enum has to have + // the suffix handing, so it slightly diverges from how nested classes work. + // enum Fixed { + // FOO = 1 + // } + // yields Fixed_Enum and Fixed_Enum_Foo (not Fixed_Foo). + const string& class_name = EnumName(descriptor->type()); + const string& value_str = UnderscoresToCamelCase(descriptor->name(), true); + const string& name = class_name + "_" + value_str; + // There aren't really any reserved words with an underscore and a leading + // capital letter, but playing it safe and checking. + return SanitizeNameForObjC(name, "_Value"); +} + +string EnumValueShortName(const EnumValueDescriptor* descriptor) { + // Enum value names (EnumValueName above) are the enum name turned into + // a class name and then the value name is CamelCased and concatenated; the + // whole thing then gets sanitized for reserved words. + // The "short name" is intended to be the final leaf, the value name; but + // you can't simply send that off to sanitize as that could result in it + // getting modified when the full name didn't. For example enum + // "StorageModes" has a value "retain". So the full name is + // "StorageModes_Retain", but if we sanitize "retain" it would become + // "RetainValue". + // So the right way to get the short name is to take the full enum name + // and then strip off the enum name (leaving the value name and anything + // done by sanitize). + const string& class_name = EnumName(descriptor->type()); + const string& long_name_prefix = class_name + "_"; + const string& long_name = EnumValueName(descriptor); + return StripPrefixString(long_name, long_name_prefix); +} + +string UnCamelCaseEnumShortName(const string& name) { + string result; + for (int i = 0; i < name.size(); i++) { + char c = name[i]; + if (i > 0 && c >= 'A' && c <= 'Z') { + result += '_'; + } + result += ToUpper(c); + } + return result; +} + +string ExtensionMethodName(const FieldDescriptor* descriptor) { + const string& name = NameFromFieldDescriptor(descriptor); + const string& result = UnderscoresToCamelCase(name, false); + return SanitizeNameForObjC(result, "_Extension"); +} + +string FieldName(const FieldDescriptor* field) { + const string& name = NameFromFieldDescriptor(field); + string result = UnderscoresToCamelCase(name, false); + if (field->is_repeated() && !field->is_map()) { + // Add "Array" before do check for reserved worlds. + result += "Array"; + } else { + // If it wasn't repeated, but ends in "Array", force on the _p suffix. + if (HasSuffixString(result, "Array")) { + result += "_p"; + } + } + return SanitizeNameForObjC(result, "_p"); +} + +string FieldNameCapitalized(const FieldDescriptor* field) { + // Want the same suffix handling, so upcase the first letter of the other + // name. + string result = FieldName(field); + if (result.length() > 0) { + result[0] = ToUpper(result[0]); + } + return result; +} + +string OneofEnumName(const OneofDescriptor* descriptor) { + const Descriptor* fieldDescriptor = descriptor->containing_type(); + string name = ClassName(fieldDescriptor); + name += "_" + UnderscoresToCamelCase(descriptor->name(), true) + "_OneOfCase"; + // No sanitize needed because it the OS never has names that end in OneOfCase. + return name; +} + +string OneofName(const OneofDescriptor* descriptor) { + string name = UnderscoresToCamelCase(descriptor->name(), false); + // No sanitize needed because it gets OneOfCase added and that shouldn't + // ever conflict. + return name; +} + +string OneofNameCapitalized(const OneofDescriptor* descriptor) { + // Use the common handling and then up-case the first letter. + string result = OneofName(descriptor); + if (result.length() > 0) { + result[0] = ToUpper(result[0]); + } + return result; +} + +string UnCamelCaseFieldName(const string& name, const FieldDescriptor* field) { + string worker(name); + if (HasSuffixString(worker, "_p")) { + worker = StripSuffixString(worker, "_p"); + } + if (field->is_repeated() && HasSuffixString(worker, "Array")) { + worker = StripSuffixString(worker, "Array"); + } + if (field->type() == FieldDescriptor::TYPE_GROUP) { + if (worker.length() > 0) { + if (worker[0] >= 'a' && worker[0] <= 'z') { + worker[0] = ToUpper(worker[0]); + } + } + return worker; + } else { + string result; + for (int i = 0; i < worker.size(); i++) { + char c = worker[i]; + if (c >= 'A' && c <= 'Z') { + if (i > 0) { + result += '_'; + } + result += ToLower(c); + } else { + result += c; + } + } + return result; + } +} + +string GetCapitalizedType(const FieldDescriptor* field) { + switch (field->type()) { + case FieldDescriptor::TYPE_INT32: + return "Int32"; + case FieldDescriptor::TYPE_UINT32: + return "UInt32"; + case FieldDescriptor::TYPE_SINT32: + return "SInt32"; + case FieldDescriptor::TYPE_FIXED32: + return "Fixed32"; + case FieldDescriptor::TYPE_SFIXED32: + return "SFixed32"; + case FieldDescriptor::TYPE_INT64: + return "Int64"; + case FieldDescriptor::TYPE_UINT64: + return "UInt64"; + case FieldDescriptor::TYPE_SINT64: + return "SInt64"; + case FieldDescriptor::TYPE_FIXED64: + return "Fixed64"; + case FieldDescriptor::TYPE_SFIXED64: + return "SFixed64"; + case FieldDescriptor::TYPE_FLOAT: + return "Float"; + case FieldDescriptor::TYPE_DOUBLE: + return "Double"; + case FieldDescriptor::TYPE_BOOL: + return "Bool"; + case FieldDescriptor::TYPE_STRING: + return "String"; + case FieldDescriptor::TYPE_BYTES: + return "Data"; + case FieldDescriptor::TYPE_ENUM: + return "Enum"; + case FieldDescriptor::TYPE_GROUP: + return "Group"; + case FieldDescriptor::TYPE_MESSAGE: + return "Message"; + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return NULL; +} + +ObjectiveCType GetObjectiveCType(FieldDescriptor::Type field_type) { + switch (field_type) { + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_SFIXED32: + return OBJECTIVECTYPE_INT32; + + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_FIXED32: + return OBJECTIVECTYPE_UINT32; + + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_SINT64: + case FieldDescriptor::TYPE_SFIXED64: + return OBJECTIVECTYPE_INT64; + + case FieldDescriptor::TYPE_UINT64: + case FieldDescriptor::TYPE_FIXED64: + return OBJECTIVECTYPE_UINT64; + + case FieldDescriptor::TYPE_FLOAT: + return OBJECTIVECTYPE_FLOAT; + + case FieldDescriptor::TYPE_DOUBLE: + return OBJECTIVECTYPE_DOUBLE; + + case FieldDescriptor::TYPE_BOOL: + return OBJECTIVECTYPE_BOOLEAN; + + case FieldDescriptor::TYPE_STRING: + return OBJECTIVECTYPE_STRING; + + case FieldDescriptor::TYPE_BYTES: + return OBJECTIVECTYPE_DATA; + + case FieldDescriptor::TYPE_ENUM: + return OBJECTIVECTYPE_ENUM; + + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_MESSAGE: + return OBJECTIVECTYPE_MESSAGE; + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return OBJECTIVECTYPE_INT32; +} + +bool IsPrimitiveType(const FieldDescriptor* field) { + ObjectiveCType type = GetObjectiveCType(field); + switch (type) { + case OBJECTIVECTYPE_INT32: + case OBJECTIVECTYPE_UINT32: + case OBJECTIVECTYPE_INT64: + case OBJECTIVECTYPE_UINT64: + case OBJECTIVECTYPE_FLOAT: + case OBJECTIVECTYPE_DOUBLE: + case OBJECTIVECTYPE_BOOLEAN: + case OBJECTIVECTYPE_ENUM: + return true; + break; + default: + return false; + } +} + +bool IsReferenceType(const FieldDescriptor* field) { + return !IsPrimitiveType(field); +} + +static string HandleExtremeFloatingPoint(string val, bool add_float_suffix) { + if (val == "nan") { + return "NAN"; + } else if (val == "inf") { + return "INFINITY"; + } else if (val == "-inf") { + return "-INFINITY"; + } else { + // float strings with ., e or E need to have f appended + if (add_float_suffix && + (val.find(".") != string::npos || val.find("e") != string::npos || + val.find("E") != string::npos)) { + val += "f"; + } + return val; + } +} + +string GPBValueFieldName(const FieldDescriptor* field) { + // Returns the field within the GPBValue union to use for the given field. + if (field->is_repeated()) { + return "valueMessage"; + } + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + return "valueInt32"; + case FieldDescriptor::CPPTYPE_UINT32: + return "valueUInt32"; + case FieldDescriptor::CPPTYPE_INT64: + return "valueInt64"; + case FieldDescriptor::CPPTYPE_UINT64: + return "valueUInt64"; + case FieldDescriptor::CPPTYPE_FLOAT: + return "valueFloat"; + case FieldDescriptor::CPPTYPE_DOUBLE: + return "valueDouble"; + case FieldDescriptor::CPPTYPE_BOOL: + return "valueBool"; + case FieldDescriptor::CPPTYPE_STRING: + if (field->type() == FieldDescriptor::TYPE_BYTES) { + return "valueData"; + } else { + return "valueString"; + } + case FieldDescriptor::CPPTYPE_ENUM: + return "valueEnum"; + case FieldDescriptor::CPPTYPE_MESSAGE: + return "valueMessage"; + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return NULL; +} + + +string DefaultValue(const FieldDescriptor* field) { + // Repeated fields don't have defaults. + if (field->is_repeated()) { + return "nil"; + } + + // Switch on cpp_type since we need to know which default_value_* method + // of FieldDescriptor to call. + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + // gcc and llvm reject the decimal form of kint32min and kint64min. + if (field->default_value_int32() == INT_MIN) { + return "-0x80000000"; + } + return SimpleItoa(field->default_value_int32()); + case FieldDescriptor::CPPTYPE_UINT32: + return SimpleItoa(field->default_value_uint32()) + "U"; + case FieldDescriptor::CPPTYPE_INT64: + // gcc and llvm reject the decimal form of kint32min and kint64min. + if (field->default_value_int64() == LLONG_MIN) { + return "-0x8000000000000000LL"; + } + return SimpleItoa(field->default_value_int64()) + "LL"; + case FieldDescriptor::CPPTYPE_UINT64: + return SimpleItoa(field->default_value_uint64()) + "ULL"; + case FieldDescriptor::CPPTYPE_DOUBLE: + return HandleExtremeFloatingPoint( + SimpleDtoa(field->default_value_double()), false); + case FieldDescriptor::CPPTYPE_FLOAT: + return HandleExtremeFloatingPoint( + SimpleFtoa(field->default_value_float()), true); + case FieldDescriptor::CPPTYPE_BOOL: + return field->default_value_bool() ? "YES" : "NO"; + case FieldDescriptor::CPPTYPE_STRING: { + const bool has_default_value = field->has_default_value(); + const string& default_string = field->default_value_string(); + if (!has_default_value || default_string.length() == 0) { + // If the field is defined as being the empty string, + // then we will just assign to nil, as the empty string is the + // default for both strings and data. + return "nil"; + } + if (field->type() == FieldDescriptor::TYPE_BYTES) { + // We want constant fields in our data structures so we can + // declare them as static. To achieve this we cheat and stuff + // a escaped c string (prefixed with a length) into the data + // field, and cast it to an (NSData*) so it will compile. + // The runtime library knows how to handle it. + + // Must convert to a standard byte order for packing length into + // a cstring. + uint32_t length = htonl(default_string.length()); + string bytes((const char*)&length, sizeof(length)); + bytes.append(default_string); + return "(NSData*)\"" + CEscape(bytes) + "\""; + } else { + return "@\"" + EscapeTrigraphs(CEscape(default_string)) + "\""; + } + } + case FieldDescriptor::CPPTYPE_ENUM: + return EnumValueName(field->default_value_enum()); + case FieldDescriptor::CPPTYPE_MESSAGE: + return "nil"; + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return NULL; +} + +string BuildFlagsString(const vector<string>& strings) { + if (strings.size() == 0) { + return "0"; + } + string string; + for (size_t i = 0; i != strings.size(); ++i) { + if (i > 0) { + string.append(" | "); + } + string.append(strings[i]); + } + return string; +} + +string BuildCommentsString(const SourceLocation& location) { + const string& comments = location.leading_comments.empty() + ? location.trailing_comments + : location.leading_comments; + vector<string> lines; + SplitStringAllowEmpty(comments, "\n", &lines); + while (!lines.empty() && lines.back().empty()) { + lines.pop_back(); + } + string prefix("//"); + string suffix("\n"); + string final_comments; + for (int i = 0; i < lines.size(); i++) { + // We use $ for delimiters, so replace comments with dollars with + // html escaped version. + // None of the other compilers handle this (as of this writing) but we + // ran into it once, so just to be safe. + final_comments += + prefix + StringReplace(lines[i], "$", "$", true) + suffix; + } + return final_comments; +} + +bool WriteClassList(string* error) { + const char* file_name = getenv("GPB_CLASSLIST_PATH"); + if (file_name != NULL) { +#ifndef O_EXLOCK + int fd = open(file_name, O_WRONLY | O_APPEND | O_CREAT, + (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)); +#else + int fd = open(file_name, O_WRONLY | O_APPEND | O_EXLOCK | O_CREAT, + (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)); +#endif + if (fd == -1) { + if (error != NULL) { + stringstream err_stream; + err_stream << endl << file_name << ":0:0: error:" + << "Unable to open (" << errno << ")"; + *error = err_stream.str(); + } + return false; + } +#ifndef O_EXLOCK + if (flock(fd, LOCK_EX) < 0) { + if (error != NULL) { + stringstream err_stream; + err_stream << endl << file_name << ":0:0: error:" + << "Unable to lock (" << errno << ")"; + *error = err_stream.str(); + } + return false; + } +#endif + // Need a local to hold the list so the cstring stays valid for the + // write call. + const string& class_list_str = gClassListStream.str(); + int write_out = write(fd, class_list_str.c_str(), class_list_str.length()); + int close_out = close(fd); + if (write_out == -1 || close_out == -1) { + if (error != NULL) { + stringstream err_stream; + err_stream << endl << file_name << ":0:0: error:" + << "Unable to write (" << errno << ")"; + *error = err_stream.str(); + } + return false; + } + } + return true; +} + +void WriteClassNameToClassList(const string& name) { + if (gClassListStream.good()) { + gClassListStream << name << '\n'; + } +} + +bool InitializeClassWhitelist(string* error) { + const char* env_var_value = getenv("GPB_OBJC_CLASS_WHITELIST_PATHS"); + if (env_var_value == NULL) { + return true; + } + + // The values are joined with ';' in case we ever want to make this a + // generator parameter also (instead of env var), and generator parameter + // parsing already has meaning for ',' and ':'. + vector<string> file_paths = Split(env_var_value, ";", true); + + for (vector<string>::const_iterator i = file_paths.begin(); + i != file_paths.end(); ++i) { + const string& file_path = *i; + + ifstream stream(file_path.c_str(), ifstream::in); + if (!stream.good()) { + if (error != NULL) { + stringstream err_stream; + err_stream << endl << file_path << ":0:0: error: Unable to open"; + *error = err_stream.str(); + return false; + } + } + + string input_line; + while (stream.good()) { + getline(stream, input_line); + string trimmed_line(TrimString(input_line)); + if (trimmed_line.length() == 0) { + // Skip empty lines + continue; + } + if (trimmed_line[0] == '/' || trimmed_line[0] == '#') { + // Skip comments and potential preprocessor symbols + continue; + } + gClassWhitelist.insert(trimmed_line); + } + } + return true; +} + +bool FilterClass(const string& name) { + if (gClassWhitelist.count(name) > 0) { + // Whitelisted, don't filter. + return false; + } + + // If there was no list, default to everything in. + // If there was a list, default to everything out. + return gClassWhitelist.size() > 0; +} + +void TextFormatDecodeData::AddString(int32_t key, + const string& input_for_decode, + const string& desired_output) { + for (vector<DataEntry>::const_iterator i = entries_.begin(); + i != entries_.end(); ++i) { + if (i->first == key) { + cerr << "error: duplicate key (" << key + << ") making TextFormat data, input: \"" << input_for_decode + << "\", desired: \"" << desired_output << "\"." << endl; + cerr.flush(); + abort(); + } + } + + const string& data = TextFormatDecodeData::DecodeDataForString( + input_for_decode, desired_output); + entries_.push_back(DataEntry(key, data)); +} + +string TextFormatDecodeData::Data() const { + ostringstream data_stringstream; + + if (num_entries() > 0) { + io::OstreamOutputStream data_outputstream(&data_stringstream); + io::CodedOutputStream output_stream(&data_outputstream); + + output_stream.WriteVarint32(num_entries()); + for (vector<DataEntry>::const_iterator i = entries_.begin(); + i != entries_.end(); ++i) { + output_stream.WriteVarint32(i->first); + output_stream.WriteString(i->second); + } + } + + data_stringstream.flush(); + return data_stringstream.str(); +} + +namespace { + +// Helper to build up the decode data for a string. +class DecodeDataBuilder { + public: + DecodeDataBuilder() { Reset(); } + + bool AddCharacter(const char desired, const char input); + void AddUnderscore() { + Push(); + need_underscore_ = true; + } + string Finish() { + Push(); + return decode_data_; + } + + private: + static const uint8_t kAddUnderscore = 0b10000000; + + static const uint8_t kOpAsIs = 0b00000000; + static const uint8_t kOpFirstUpper = 0b01000000; + static const uint8_t kOpFirstLower = 0b00100000; + static const uint8_t kOpAllUpper = 0b01100000; + + static const int kMaxSegmentLen = 0b00011111; + + void AddChar(const char desired) { + ++segment_len_; + is_all_upper_ &= IsUpper(desired); + } + + void Push() { + uint8_t op = (op_ | segment_len_); + if (need_underscore_) op |= kAddUnderscore; + if (op != 0) { + decode_data_ += (char)op; + } + Reset(); + } + + bool AddFirst(const char desired, const char input) { + if (desired == input) { + op_ = kOpAsIs; + } else if (desired == ToUpper(input)) { + op_ = kOpFirstUpper; + } else if (desired == ToLower(input)) { + op_ = kOpFirstLower; + } else { + // Can't be transformed to match. + return false; + } + AddChar(desired); + return true; + } + + void Reset() { + need_underscore_ = false; + op_ = 0; + segment_len_ = 0; + is_all_upper_ = true; + } + + bool need_underscore_; + bool is_all_upper_; + uint8_t op_; + int segment_len_; + + string decode_data_; +}; + +bool DecodeDataBuilder::AddCharacter(const char desired, const char input) { + // If we've hit the max size, push to start a new segment. + if (segment_len_ == kMaxSegmentLen) { + Push(); + } + if (segment_len_ == 0) { + return AddFirst(desired, input); + } + + // Desired and input match... + if (desired == input) { + // If we aren't transforming it, or we're upper casing it and it is + // supposed to be uppercase; just add it to the segment. + if ((op_ != kOpAllUpper) || IsUpper(desired)) { + AddChar(desired); + return true; + } + + // Add the current segment, and start the next one. + Push(); + return AddFirst(desired, input); + } + + // If we need to uppercase, and everything so far has been uppercase, + // promote op to AllUpper. + if ((desired == ToUpper(input)) && is_all_upper_) { + op_ = kOpAllUpper; + AddChar(desired); + return true; + } + + // Give up, push and start a new segment. + Push(); + return AddFirst(desired, input); +} + +// If decode data can't be generated, a directive for the raw string +// is used instead. +string DirectDecodeString(const string& str) { + string result; + result += (char)'\0'; // Marker for full string. + result += str; + result += (char)'\0'; // End of string. + return result; +} + +} // namespace + +// static +string TextFormatDecodeData::DecodeDataForString(const string& input_for_decode, + const string& desired_output) { + if ((input_for_decode.size() == 0) || (desired_output.size() == 0)) { + cerr << "error: got empty string for making TextFormat data, input: \"" + << input_for_decode << "\", desired: \"" << desired_output << "\"." + << endl; + cerr.flush(); + abort(); + } + if ((input_for_decode.find('\0') != string::npos) || + (desired_output.find('\0') != string::npos)) { + cerr << "error: got a null char in a string for making TextFormat data," + << " input: \"" << CEscape(input_for_decode) << "\", desired: \"" + << CEscape(desired_output) << "\"." << endl; + cerr.flush(); + abort(); + } + + DecodeDataBuilder builder; + + // Walk the output building it from the input. + int x = 0; + for (int y = 0; y < desired_output.size(); y++) { + const char d = desired_output[y]; + if (d == '_') { + builder.AddUnderscore(); + continue; + } + + if (x >= input_for_decode.size()) { + // Out of input, no way to encode it, just return a full decode. + return DirectDecodeString(desired_output); + } + if (builder.AddCharacter(d, input_for_decode[x])) { + ++x; // Consumed one input + } else { + // Couldn't transform for the next character, just return a full decode. + return DirectDecodeString(desired_output); + } + } + + if (x != input_for_decode.size()) { + // Extra input (suffix from name sanitizing?), just return a full decode. + return DirectDecodeString(desired_output); + } + + // Add the end marker. + return builder.Finish() + (char)'\0'; +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h new file mode 100644 index 00000000..2701a30c --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h @@ -0,0 +1,176 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__ + +#include <string> +#include <vector> + +#include <google/protobuf/descriptor.h> +#include <google/protobuf/descriptor.pb.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +// Strips ".proto" or ".protodevel" from the end of a filename. +string StripProto(const string& filename); + +// Returns true if the name requires a ns_returns_not_retained attribute applied +// to it. +bool IsRetainedName(const string& name); + +// Returns true if the name starts with "init" and will need to have special +// handling under ARC. +bool IsInitName(const string& name); + +// Gets the name of the file we're going to generate (sans the .pb.h +// extension). This does not include the path to that file. +string FileName(const FileDescriptor* file); + +// Gets the path of the file we're going to generate (sans the .pb.h +// extension). The path will be dependent on the objectivec package +// declared in the proto package. +string FilePath(const FileDescriptor* file); + +// Gets the name of the root class we'll generate in the file. This class +// is not meant for external consumption, but instead contains helpers that +// the rest of the the classes need +string FileClassName(const FileDescriptor* file); + +// These return the fully-qualified class name corresponding to the given +// descriptor. +string ClassName(const Descriptor* descriptor); +string EnumName(const EnumDescriptor* descriptor); + +// Returns the fully-qualified name of the enum value corresponding to the +// the descriptor. +string EnumValueName(const EnumValueDescriptor* descriptor); + +// Returns the name of the enum value corresponding to the descriptor. +string EnumValueShortName(const EnumValueDescriptor* descriptor); + +// Reverse what an enum does. +string UnCamelCaseEnumShortName(const string& name); + +// Returns the name to use for the extension (used as the method off the file's +// Root class). +string ExtensionMethodName(const FieldDescriptor* descriptor); + +// Returns the transformed field name. +string FieldName(const FieldDescriptor* field); +string FieldNameCapitalized(const FieldDescriptor* field); + +// Returns the transformed oneof name. +string OneofEnumName(const OneofDescriptor* descriptor); +string OneofName(const OneofDescriptor* descriptor); +string OneofNameCapitalized(const OneofDescriptor* descriptor); + +inline bool HasFieldPresence(const FileDescriptor* file) { + return file->syntax() != FileDescriptor::SYNTAX_PROTO3; +} + +inline bool HasPreservingUnknownEnumSemantics(const FileDescriptor* file) { + return file->syntax() == FileDescriptor::SYNTAX_PROTO3; +} + +inline bool IsMapEntryMessage(const Descriptor* descriptor) { + return descriptor->options().map_entry(); +} + +// Reverse of the above. +string UnCamelCaseFieldName(const string& name, const FieldDescriptor* field); + +enum ObjectiveCType { + OBJECTIVECTYPE_INT32, + OBJECTIVECTYPE_UINT32, + OBJECTIVECTYPE_INT64, + OBJECTIVECTYPE_UINT64, + OBJECTIVECTYPE_FLOAT, + OBJECTIVECTYPE_DOUBLE, + OBJECTIVECTYPE_BOOLEAN, + OBJECTIVECTYPE_STRING, + OBJECTIVECTYPE_DATA, + OBJECTIVECTYPE_ENUM, + OBJECTIVECTYPE_MESSAGE +}; + +string GetCapitalizedType(const FieldDescriptor* field); + +ObjectiveCType GetObjectiveCType(FieldDescriptor::Type field_type); + +inline ObjectiveCType GetObjectiveCType(const FieldDescriptor* field) { + return GetObjectiveCType(field->type()); +} + +bool IsPrimitiveType(const FieldDescriptor* field); +bool IsReferenceType(const FieldDescriptor* field); + +string GPBValueFieldName(const FieldDescriptor* field); +string DefaultValue(const FieldDescriptor* field); + +string BuildFlagsString(const vector<string>& strings); + +string BuildCommentsString(const SourceLocation& location); + +bool WriteClassList(string* error); +void WriteClassNameToClassList(const string& name); + +bool InitializeClassWhitelist(string* error); +bool FilterClass(const string& name); + +// Generate decode data needed for ObjC's GPBDecodeTextFormatName() to transform +// the input into the the expected output. +class TextFormatDecodeData { + public: + TextFormatDecodeData() {} + + void AddString(int32_t key, const string& input_for_decode, + const string& desired_output); + size_t num_entries() const { return entries_.size(); } + string Data() const; + + static string DecodeDataForString(const string& input_for_decode, + const string& desired_output); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TextFormatDecodeData); + + typedef std::pair<int32_t, string> DataEntry; + vector<DataEntry> entries_; +}; + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_HELPERS_H__ diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc new file mode 100644 index 00000000..c9682b08 --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc @@ -0,0 +1,242 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 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. + +#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> +#include <google/protobuf/testing/googletest.h> +#include <gtest/gtest.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { +namespace { + +TEST(ObjCHelper, TextFormatDecodeData_DecodeDataForString_RawStrings) { + string input_for_decode("abcdefghIJ"); + string desired_output_for_decode; + string expected; + string result; + + // Different data, can't transform. + + desired_output_for_decode = "zbcdefghIJ"; + expected = string("\0zbcdefghIJ\0", 12); + result = TextFormatDecodeData::DecodeDataForString(input_for_decode, + desired_output_for_decode); + EXPECT_EQ(expected, result); + + desired_output_for_decode = "abcdezghIJ"; + expected = string("\0abcdezghIJ\0", 12); + result = TextFormatDecodeData::DecodeDataForString(input_for_decode, + desired_output_for_decode); + EXPECT_EQ(expected, result); + + // Shortened data, can't transform. + + desired_output_for_decode = "abcdefghI"; + expected = string("\0abcdefghI\0", 11); + result = TextFormatDecodeData::DecodeDataForString(input_for_decode, + desired_output_for_decode); + EXPECT_EQ(expected, result); + + // Extra data, can't transform. + + desired_output_for_decode = "abcdefghIJz"; + expected = string("\0abcdefghIJz\0", 13); + result = TextFormatDecodeData::DecodeDataForString(input_for_decode, + desired_output_for_decode); + EXPECT_EQ(expected, result); +} + +TEST(ObjCHelper, TextFormatDecodeData_DecodeDataForString_ByteCodes) { + string input_for_decode("abcdefghIJ"); + string desired_output_for_decode; + string expected; + string result; + + desired_output_for_decode = "abcdefghIJ"; + expected = string("\x0A\x0", 2); + result = TextFormatDecodeData::DecodeDataForString(input_for_decode, + desired_output_for_decode); + EXPECT_EQ(expected, result); + + desired_output_for_decode = "_AbcdefghIJ"; + expected = string("\xCA\x0", 2); + result = TextFormatDecodeData::DecodeDataForString(input_for_decode, + desired_output_for_decode); + EXPECT_EQ(expected, result); + + desired_output_for_decode = "ABCD__EfghI_j"; + expected = string("\x64\x80\xC5\xA1\x0", 5); + result = TextFormatDecodeData::DecodeDataForString(input_for_decode, + desired_output_for_decode); + EXPECT_EQ(expected, result); + + // Long name so multiple decode ops are needed. + + input_for_decode = + "longFieldNameIsLooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong1000"; + desired_output_for_decode = + "long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_1000"; + expected = string("\x04\xA5\xA4\xA2\xBF\x1F\x0E\x84\x0", 9); + result = TextFormatDecodeData::DecodeDataForString(input_for_decode, + desired_output_for_decode); + EXPECT_EQ(expected, result); +} + +TEST(ObjCHelperDeathTest, TextFormatDecodeData_DecodeDataForString_Failures) { + // Empty inputs. + + EXPECT_EXIT(TextFormatDecodeData::DecodeDataForString("", ""), + ::testing::KilledBySignal(SIGABRT), + "error: got empty string for making TextFormat data, input:"); + EXPECT_EXIT(TextFormatDecodeData::DecodeDataForString("a", ""), + ::testing::KilledBySignal(SIGABRT), + "error: got empty string for making TextFormat data, input:"); + EXPECT_EXIT(TextFormatDecodeData::DecodeDataForString("", "a"), + ::testing::KilledBySignal(SIGABRT), + "error: got empty string for making TextFormat data, input:"); + + // Null char in the string. + + string str_with_null_char("ab\0c", 4); + EXPECT_EXIT( + TextFormatDecodeData::DecodeDataForString(str_with_null_char, "def"), + ::testing::KilledBySignal(SIGABRT), + "error: got a null char in a string for making TextFormat data, input:"); + EXPECT_EXIT( + TextFormatDecodeData::DecodeDataForString("def", str_with_null_char), + ::testing::KilledBySignal(SIGABRT), + "error: got a null char in a string for making TextFormat data, input:"); +} + +TEST(ObjCHelper, TextFormatDecodeData_RawStrings) { + TextFormatDecodeData decode_data; + + // Different data, can't transform. + decode_data.AddString(1, "abcdefghIJ", "zbcdefghIJ"); + decode_data.AddString(3, "abcdefghIJ", "abcdezghIJ"); + // Shortened data, can't transform. + decode_data.AddString(2, "abcdefghIJ", "abcdefghI"); + // Extra data, can't transform. + decode_data.AddString(4, "abcdefghIJ", "abcdefghIJz"); + + EXPECT_EQ(4, decode_data.num_entries()); + + uint8_t expected_data[] = { + 0x4, + 0x1, 0x0, 'z', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'I', 'J', 0x0, + 0x3, 0x0, 'a', 'b', 'c', 'd', 'e', 'z', 'g', 'h', 'I', 'J', 0x0, + 0x2, 0x0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'I', 0x0, + 0x4, 0x0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'I', 'J', 'z', 0x0, + }; + string expected((const char*)expected_data, sizeof(expected_data)); + + EXPECT_EQ(expected, decode_data.Data()); +} + +TEST(ObjCHelper, TextFormatDecodeData_ByteCodes) { + TextFormatDecodeData decode_data; + + decode_data.AddString(1, "abcdefghIJ", "abcdefghIJ"); + decode_data.AddString(3, "abcdefghIJ", "_AbcdefghIJ"); + decode_data.AddString(2, "abcdefghIJ", "Abcd_EfghIJ"); + decode_data.AddString(4, "abcdefghIJ", "ABCD__EfghI_j"); + decode_data.AddString(1000, + "longFieldNameIsLooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong1000", + "long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_1000"); + + EXPECT_EQ(5, decode_data.num_entries()); + + uint8_t expected_data[] = { + 0x5, + // All as is (00 op) + 0x1, 0x0A, 0x0, + // Underscore, upper + 9 (10 op) + 0x3, 0xCA, 0x0, + // Upper + 3 (10 op), underscore, upper + 5 (10 op) + 0x2, 0x44, 0xC6, 0x0, + // All Upper for 4 (11 op), underscore, underscore, upper + 5 (10 op), + // underscore, lower + 0 (01 op) + 0x4, 0x64, 0x80, 0xC5, 0xA1, 0x0, + // 2 byte key: as is + 3 (00 op), underscore, lower + 4 (01 op), + // underscore, lower + 3 (01 op), underscore, lower + 1 (01 op), + // underscore, lower + 30 (01 op), as is + 30 (00 op), as is + 13 (00 + // op), + // underscore, as is + 3 (00 op) + 0xE8, 0x07, 0x04, 0xA5, 0xA4, 0xA2, 0xBF, 0x1F, 0x0E, 0x84, 0x0, + }; + string expected((const char*)expected_data, sizeof(expected_data)); + + EXPECT_EQ(expected, decode_data.Data()); +} + +TEST(ObjCHelperDeathTest, TextFormatDecodeData_Failures) { + TextFormatDecodeData decode_data; + + // Empty inputs. + + EXPECT_EXIT(decode_data.AddString(1, "", ""), + ::testing::KilledBySignal(SIGABRT), + "error: got empty string for making TextFormat data, input:"); + EXPECT_EXIT(decode_data.AddString(1, "a", ""), + ::testing::KilledBySignal(SIGABRT), + "error: got empty string for making TextFormat data, input:"); + EXPECT_EXIT(decode_data.AddString(1, "", "a"), + ::testing::KilledBySignal(SIGABRT), + "error: got empty string for making TextFormat data, input:"); + + // Null char in the string. + + string str_with_null_char("ab\0c", 4); + EXPECT_EXIT( + decode_data.AddString(1, str_with_null_char, "def"), + ::testing::KilledBySignal(SIGABRT), + "error: got a null char in a string for making TextFormat data, input:"); + EXPECT_EXIT( + decode_data.AddString(1, "def", str_with_null_char), + ::testing::KilledBySignal(SIGABRT), + "error: got a null char in a string for making TextFormat data, input:"); + + // Duplicate keys + + decode_data.AddString(1, "abcdefghIJ", "abcdefghIJ"); + decode_data.AddString(3, "abcdefghIJ", "_AbcdefghIJ"); + decode_data.AddString(2, "abcdefghIJ", "Abcd_EfghIJ"); + EXPECT_EXIT(decode_data.AddString(2, "xyz", "x_yz"), + ::testing::KilledBySignal(SIGABRT), + "error: duplicate key \\(2\\) making TextFormat data, input:"); +} + +} // namespace +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc new file mode 100644 index 00000000..cafdf39d --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc @@ -0,0 +1,161 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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. + +#include <map> +#include <string> + +#include <google/protobuf/compiler/objectivec/objectivec_map_field.h> +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/substitute.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +// MapFieldGenerator uses RepeatedFieldGenerator as the parent because it +// provides a bunch of things (no has* methods, comments for contained type, +// etc.). + +namespace { + +const char* MapEntryTypeName(const FieldDescriptor* descriptor, bool isKey) { + ObjectiveCType type = GetObjectiveCType(descriptor); + switch (type) { + case OBJECTIVECTYPE_INT32: + return "Int32"; + case OBJECTIVECTYPE_UINT32: + return "UInt32"; + case OBJECTIVECTYPE_INT64: + return "Int64"; + case OBJECTIVECTYPE_UINT64: + return "UInt64"; + case OBJECTIVECTYPE_FLOAT: + return "Float"; + case OBJECTIVECTYPE_DOUBLE: + return "Double"; + case OBJECTIVECTYPE_BOOLEAN: + return "Bool"; + case OBJECTIVECTYPE_STRING: + return (isKey ? "String" : "Object"); + case OBJECTIVECTYPE_DATA: + return "Object"; + case OBJECTIVECTYPE_ENUM: + return "Enum"; + case OBJECTIVECTYPE_MESSAGE: + return "Object"; + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return NULL; +} + +} // namespace + +MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor) + : RepeatedFieldGenerator(descriptor) { + const FieldDescriptor* key_descriptor = + descriptor->message_type()->FindFieldByName("key"); + const FieldDescriptor* value_descriptor = + descriptor->message_type()->FindFieldByName("value"); + value_field_generator_.reset(FieldGenerator::Make(value_descriptor)); + + // Pull over some variables_ from the value. + variables_["field_type"] = value_field_generator_->variable("field_type"); + variables_["default"] = value_field_generator_->variable("default"); + variables_["default_name"] = value_field_generator_->variable("default_name"); + + // Build custom field flags. + std::vector<string> field_flags; + field_flags.push_back("GPBFieldMapKey" + GetCapitalizedType(key_descriptor)); + // Pull over the current text format custom name values that was calculated. + if (variables_["fieldflags"].find("GPBFieldTextFormatNameCustom") != + string::npos) { + field_flags.push_back("GPBFieldTextFormatNameCustom"); + } + // Pull over some info from the value's flags. + const string& value_field_flags = + value_field_generator_->variable("fieldflags"); + if (value_field_flags.find("GPBFieldHasDefaultValue") != string::npos) { + field_flags.push_back("GPBFieldHasDefaultValue"); + } + if (value_field_flags.find("GPBFieldHasEnumDescriptor") != string::npos) { + field_flags.push_back("GPBFieldHasEnumDescriptor"); + } + variables_["fieldflags"] = BuildFlagsString(field_flags); + + ObjectiveCType value_objc_type = GetObjectiveCType(value_descriptor); + if ((GetObjectiveCType(key_descriptor) == OBJECTIVECTYPE_STRING) && + ((value_objc_type == OBJECTIVECTYPE_STRING) || + (value_objc_type == OBJECTIVECTYPE_DATA) || + (value_objc_type == OBJECTIVECTYPE_MESSAGE))) { + variables_["array_storage_type"] = "NSMutableDictionary"; + } else { + string base_name = MapEntryTypeName(key_descriptor, true); + base_name += MapEntryTypeName(value_descriptor, false); + base_name += "Dictionary"; + variables_["array_storage_type"] = "GPB" + base_name; + } +} + +MapFieldGenerator::~MapFieldGenerator() {} + +void MapFieldGenerator::FinishInitialization(void) { + RepeatedFieldGenerator::FinishInitialization(); + // Use the array_comment suport in RepeatedFieldGenerator to output what the + // values in the map are. + const FieldDescriptor* value_descriptor = + descriptor_->message_type()->FindFieldByName("value"); + ObjectiveCType value_objc_type = GetObjectiveCType(value_descriptor); + if ((value_objc_type == OBJECTIVECTYPE_MESSAGE) || + (value_objc_type == OBJECTIVECTYPE_DATA) || + (value_objc_type == OBJECTIVECTYPE_STRING) || + (value_objc_type == OBJECTIVECTYPE_ENUM)) { + variables_["array_comment"] = + "// |" + variables_["name"] + "| values are |" + value_field_generator_->variable("storage_type") + "|\n"; + } else { + variables_["array_comment"] = ""; + } +} + +void MapFieldGenerator::GenerateFieldDescriptionTypeSpecific( + io::Printer* printer) const { + // Relay it to the value generator to provide enum validator, message + // class, etc. + value_field_generator_->GenerateFieldDescriptionTypeSpecific(printer); +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.h b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h new file mode 100644 index 00000000..8862dc35 --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h @@ -0,0 +1,64 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MAP_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MAP_FIELD_H__ + +#include <map> +#include <string> +#include <google/protobuf/compiler/objectivec/objectivec_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +class MapFieldGenerator : public RepeatedFieldGenerator { + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + + public: + virtual void FinishInitialization(void); + virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const; + + protected: + MapFieldGenerator(const FieldDescriptor* descriptor); + virtual ~MapFieldGenerator(); + + private: + scoped_ptr<FieldGenerator> value_field_generator_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator); +}; + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MAP_FIELD_H__ diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.cc b/src/google/protobuf/compiler/objectivec/objectivec_message.cc new file mode 100644 index 00000000..87e4d0f8 --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_message.cc @@ -0,0 +1,642 @@ +// 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. + +#include <algorithm> +#include <iostream> +#include <sstream> + +#include <google/protobuf/stubs/hash.h> +#include <google/protobuf/compiler/objectivec/objectivec_message.h> +#include <google/protobuf/compiler/objectivec/objectivec_enum.h> +#include <google/protobuf/compiler/objectivec/objectivec_extension.h> +#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> +#include <google/protobuf/stubs/stl_util.h> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/coded_stream.h> +#include <google/protobuf/io/zero_copy_stream_impl.h> +#include <google/protobuf/wire_format.h> +#include <google/protobuf/wire_format_lite_inl.h> +#include <google/protobuf/descriptor.pb.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +using internal::WireFormat; +using internal::WireFormatLite; + +namespace { +struct FieldOrderingByNumber { + inline bool operator()(const FieldDescriptor* a, + const FieldDescriptor* b) const { + return a->number() < b->number(); + } +}; + +int OrderGroupForFieldDescriptor(const FieldDescriptor* descriptor) { + // The first item in the object structure is our uint32[] for has bits. + // We then want to order things to make the instances as small as + // possible. So we follow the has bits with: + // 1. Bools (1 byte) + // 2. Anything always 4 bytes - float, *32, enums + // 3. Anything that is always a pointer (they will be 8 bytes on 64 bit + // builds and 4 bytes on 32bit builds. + // 4. Anything always 8 bytes - double, *64 + // + // Why? Using 64bit builds as an example, this means worse case, we have + // enough bools that we overflow 1 byte from 4 byte alignment, so 3 bytes + // are wasted before the 4 byte values. Then if we have an odd number of + // those 4 byte values, the 8 byte values will be pushed down by 32bits to + // keep them aligned. But the structure will end 8 byte aligned, so no + // waste on the end. If you did the reverse order, you could waste 4 bytes + // before the first 8 byte value (after the has array), then a single + // bool on the end would need 7 bytes of padding to make the overall + // structure 8 byte aligned; so 11 bytes, wasted total. + + // Anything repeated is a GPB*Array/NSArray, so pointer. + if (descriptor->is_repeated()) { + return 3; + } + + switch (descriptor->type()) { + // All always 8 bytes. + case FieldDescriptor::TYPE_DOUBLE: + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_SINT64: + case FieldDescriptor::TYPE_UINT64: + case FieldDescriptor::TYPE_SFIXED64: + case FieldDescriptor::TYPE_FIXED64: + return 4; + + // Pointers (string and bytes are NSString and NSData); 8 or 4 bytes + // depending on the build architecture. + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: + return 3; + + // All always 4 bytes (enums are int32s). + case FieldDescriptor::TYPE_FLOAT: + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_SFIXED32: + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_ENUM: + return 2; + + // 1 byte. + case FieldDescriptor::TYPE_BOOL: + return 1; + } +} + +struct FieldOrderingByStorageSize { + inline bool operator()(const FieldDescriptor* a, + const FieldDescriptor* b) const { + // Order by grouping. + const int order_group_a = OrderGroupForFieldDescriptor(a); + const int order_group_b = OrderGroupForFieldDescriptor(b); + if (order_group_a != order_group_b) { + return order_group_a < order_group_b; + } + // Within the group, order by field number (provides stable ordering). + return a->number() < b->number(); + } +}; + +struct ExtensionRangeOrdering { + bool operator()(const Descriptor::ExtensionRange* a, + const Descriptor::ExtensionRange* b) const { + return a->start < b->start; + } +}; + +// Sort the fields of the given Descriptor by number into a new[]'d array +// and return it. +const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) { + const FieldDescriptor** fields = + new const FieldDescriptor* [descriptor->field_count()]; + for (int i = 0; i < descriptor->field_count(); i++) { + fields[i] = descriptor->field(i); + } + sort(fields, fields + descriptor->field_count(), FieldOrderingByNumber()); + return fields; +} + +// Sort the fields of the given Descriptor by storage size into a new[]'d +// array and return it. +const FieldDescriptor** SortFieldsByStorageSize(const Descriptor* descriptor) { + const FieldDescriptor** fields = + new const FieldDescriptor* [descriptor->field_count()]; + for (int i = 0; i < descriptor->field_count(); i++) { + fields[i] = descriptor->field(i); + } + sort(fields, fields + descriptor->field_count(), + FieldOrderingByStorageSize()); + return fields; +} +} // namespace + +MessageGenerator::MessageGenerator(const string& root_classname, + const Descriptor* descriptor) + : root_classname_(root_classname), + descriptor_(descriptor), + field_generators_(descriptor), + class_name_(ClassName(descriptor_)), + sub_content_filtered_(true) { + if (FilterClass(class_name_)) { + filter_reason_ = + string("Message |") + class_name_ + "| was not whitelisted."; + } + if (!IsFiltered()) { + // No need to generate extensions if this message is filtered + for (int i = 0; i < descriptor_->extension_count(); i++) { + extension_generators_.push_back( + new ExtensionGenerator(class_name_, descriptor_->extension(i))); + } + // No need to oneofs if this message is filtered + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + OneofGenerator* generator = new OneofGenerator(descriptor_->oneof_decl(i)); + oneof_generators_.push_back(generator); + } + } + + // We may have enums of this message that are used even if the message + // itself is filtered. + for (int i = 0; i < descriptor_->enum_type_count(); i++) { + EnumGenerator* generator = new EnumGenerator(descriptor_->enum_type(i)); + // The enums are exposed via C functions, so they will dead strip if + // not used. + sub_content_filtered_ &= false; + enum_generators_.push_back(generator); + } + + // We may have nested messages that are used even if the message itself + // is filtered. + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + const Descriptor* nested_descriptor = descriptor_->nested_type(i); + MessageGenerator* generator = + new MessageGenerator(root_classname_, nested_descriptor); + // Don't check map entries for being filtered, as they don't directly + // generate anything in Objective C. In theory, they only should include + // references to other toplevel types, but we still make the generators + // to be safe. + if (!IsMapEntryMessage(nested_descriptor)) { + sub_content_filtered_ &= generator->IsFiltered(); + } + sub_content_filtered_ &= generator->IsSubContentFiltered(); + nested_message_generators_.push_back(generator); + } +} + +MessageGenerator::~MessageGenerator() { + STLDeleteContainerPointers(extension_generators_.begin(), + extension_generators_.end()); + STLDeleteContainerPointers(enum_generators_.begin(), enum_generators_.end()); + STLDeleteContainerPointers(nested_message_generators_.begin(), + nested_message_generators_.end()); + STLDeleteContainerPointers(oneof_generators_.begin(), + oneof_generators_.end()); +} + +void MessageGenerator::GenerateStaticVariablesInitialization( + io::Printer* printer, bool* out_generated) { + if (!IsFiltered()) { + // Skip extensions if we are filtered. + for (vector<ExtensionGenerator*>::iterator iter = + extension_generators_.begin(); + iter != extension_generators_.end(); ++iter) { + (*iter)->GenerateStaticVariablesInitialization(printer, out_generated, + false); + } + } + + // Generating sub messages is perfectly fine though. + for (vector<MessageGenerator*>::iterator iter = + nested_message_generators_.begin(); + iter != nested_message_generators_.end(); ++iter) { + (*iter)->GenerateStaticVariablesInitialization(printer, out_generated); + } +} + +void MessageGenerator::DetermineDependencies(set<string>* dependencies) { + if (!IsFiltered() && !IsMapEntryMessage(descriptor_)) { + dependencies->insert("@class " + class_name_); + } + + for (vector<MessageGenerator*>::iterator iter = + nested_message_generators_.begin(); + iter != nested_message_generators_.end(); ++iter) { + (*iter)->DetermineDependencies(dependencies); + } +} + +void MessageGenerator::GenerateEnumHeader(io::Printer* printer) { + for (vector<EnumGenerator*>::iterator iter = enum_generators_.begin(); + iter != enum_generators_.end(); ++iter) { + (*iter)->GenerateHeader(printer); + } + + for (vector<MessageGenerator*>::iterator iter = + nested_message_generators_.begin(); + iter != nested_message_generators_.end(); ++iter) { + (*iter)->GenerateEnumHeader(printer); + } +} + +void MessageGenerator::GenerateExtensionRegistrationSource( + io::Printer* printer) { + if (!IsFiltered()) { + for (vector<ExtensionGenerator*>::iterator iter = + extension_generators_.begin(); + iter != extension_generators_.end(); ++iter) { + (*iter)->GenerateRegistrationSource(printer); + } + } + + for (vector<MessageGenerator*>::iterator iter = + nested_message_generators_.begin(); + iter != nested_message_generators_.end(); ++iter) { + (*iter)->GenerateExtensionRegistrationSource(printer); + } +} + +void MessageGenerator::GenerateMessageHeader(io::Printer* printer) { + // This a a map entry message, just recurse and do nothing directly. + if (IsMapEntryMessage(descriptor_)) { + for (vector<MessageGenerator*>::iterator iter = + nested_message_generators_.begin(); + iter != nested_message_generators_.end(); ++iter) { + (*iter)->GenerateMessageHeader(printer); + } + return; + } + + WriteClassNameToClassList(class_name_); + + if (IsFiltered()) { + printer->Print("// $filter_reason$\n\n", + "filter_reason", filter_reason_); + } else { + printer->Print( + "#pragma mark - $classname$\n" + "\n", + "classname", class_name_); + + if (descriptor_->field_count()) { + // Even if there are fields, they could be filtered away, so always use + // a buffer to confirm we have something. + ostringstream fieldnumber_stringstream; + { + scoped_array<const FieldDescriptor*> sorted_fields( + SortFieldsByNumber(descriptor_)); + + io::OstreamOutputStream fieldnumber_outputstream( + &fieldnumber_stringstream); + io::Printer fieldnumber_printer(&fieldnumber_outputstream, '$'); + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(sorted_fields[i]) + .GenerateFieldNumberConstant(&fieldnumber_printer); + } + fieldnumber_stringstream.flush(); + } + const string& fieldnumber_str = fieldnumber_stringstream.str(); + if (fieldnumber_str.length()) { + printer->Print("typedef GPB_ENUM($classname$_FieldNumber) {\n", + "classname", class_name_); + printer->Indent(); + printer->Print(fieldnumber_str.c_str()); + printer->Outdent(); + printer->Print("};\n\n"); + } + } + + for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin(); + iter != oneof_generators_.end(); ++iter) { + (*iter)->GenerateCaseEnum(printer); + } + + string message_comments; + SourceLocation location; + if (descriptor_->GetSourceLocation(&location)) { + message_comments = BuildCommentsString(location); + } else { + message_comments = ""; + } + + printer->Print( + "$comments$@interface $classname$ : GPBMessage\n\n", + "classname", class_name_, + "comments", message_comments); + + vector<bool> seen_oneofs(descriptor_->oneof_decl_count(), false); + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + if (field->containing_oneof() != NULL) { + const int oneof_index = field->containing_oneof()->index(); + if (!seen_oneofs[oneof_index]) { + seen_oneofs[oneof_index] = true; + oneof_generators_[oneof_index]->GeneratePublicCasePropertyDeclaration( + printer); + } + } + field_generators_.get(field) + .GeneratePropertyDeclaration(printer); + } + + printer->Print("@end\n\n"); + + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(descriptor_->field(i)) + .GenerateCFunctionDeclarations(printer); + } + + if (!oneof_generators_.empty()) { + for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin(); + iter != oneof_generators_.end(); ++iter) { + (*iter)->GenerateClearFunctionDeclaration(printer); + } + printer->Print("\n"); + } + + if (descriptor_->extension_count() > 0) { + printer->Print("@interface $classname$ (DynamicMethods)\n\n", + "classname", class_name_); + for (vector<ExtensionGenerator*>::iterator iter = + extension_generators_.begin(); + iter != extension_generators_.end(); ++iter) { + (*iter)->GenerateMembersHeader(printer); + } + printer->Print("@end\n\n"); + } + } + + for (vector<MessageGenerator*>::iterator iter = + nested_message_generators_.begin(); + iter != nested_message_generators_.end(); ++iter) { + (*iter)->GenerateMessageHeader(printer); + } +} + +void MessageGenerator::GenerateSource(io::Printer* printer) { + if (!IsFiltered() && !IsMapEntryMessage(descriptor_)) { + printer->Print( + "#pragma mark - $classname$\n" + "\n", + "classname", class_name_); + + printer->Print("@implementation $classname$\n\n", + "classname", class_name_); + + for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin(); + iter != oneof_generators_.end(); ++iter) { + (*iter)->GeneratePropertyImplementation(printer); + } + + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(descriptor_->field(i)) + .GeneratePropertyImplementation(printer); + } + + scoped_array<const FieldDescriptor*> sorted_fields( + SortFieldsByNumber(descriptor_)); + scoped_array<const FieldDescriptor*> size_order_fields( + SortFieldsByStorageSize(descriptor_)); + + vector<const Descriptor::ExtensionRange*> sorted_extensions; + for (int i = 0; i < descriptor_->extension_range_count(); ++i) { + sorted_extensions.push_back(descriptor_->extension_range(i)); + } + + sort(sorted_extensions.begin(), sorted_extensions.end(), + ExtensionRangeOrdering()); + + size_t num_has_bits = descriptor_->field_count(); + size_t sizeof_has_storage = (num_has_bits + 31) / 32; + // Tell all the fields the oneof base. + for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin(); + iter != oneof_generators_.end(); ++iter) { + (*iter)->SetOneofIndexBase(sizeof_has_storage); + } + field_generators_.SetOneofIndexBase(sizeof_has_storage); + // Add an int32 for each oneof to store which is set. + sizeof_has_storage += descriptor_->oneof_decl_count(); + + printer->Print( + "\n" + "typedef struct $classname$_Storage {\n" + " uint32_t _has_storage_[$sizeof_has_storage$];\n", + "classname", class_name_, + "sizeof_has_storage", SimpleItoa(sizeof_has_storage)); + printer->Indent(); + + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(size_order_fields[i]) + .GenerateFieldStorageDeclaration(printer); + } + printer->Outdent(); + + printer->Print("} $classname$_Storage;\n\n", "classname", class_name_); + + + printer->Print( + "// This method is threadsafe because it is initially called\n" + "// in +initialize for each subclass.\n" + "+ (GPBDescriptor *)descriptor {\n" + " static GPBDescriptor *descriptor = NULL;\n" + " if (!descriptor) {\n"); + + bool has_oneofs = oneof_generators_.size(); + if (has_oneofs) { + printer->Print( + " static GPBMessageOneofDescription oneofs[] = {\n"); + printer->Indent(); + printer->Indent(); + printer->Indent(); + for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin(); + iter != oneof_generators_.end(); ++iter) { + (*iter)->GenerateDescription(printer); + } + printer->Outdent(); + printer->Outdent(); + printer->Outdent(); + printer->Print( + " };\n"); + } + + printer->Print( + " static GPBMessageFieldDescription fields[] = {\n"); + printer->Indent(); + printer->Indent(); + printer->Indent(); + TextFormatDecodeData text_format_decode_data; + for (int i = 0; i < descriptor_->field_count(); ++i) { + const FieldGenerator& field_generator = + field_generators_.get(sorted_fields[i]); + field_generator.GenerateFieldDescription(printer); + if (field_generator.needs_textformat_name_support()) { + text_format_decode_data.AddString(sorted_fields[i]->number(), + field_generator.generated_objc_name(), + field_generator.raw_field_name()); + } + } + printer->Outdent(); + printer->Outdent(); + printer->Outdent(); + + bool has_enums = enum_generators_.size(); + if (has_enums) { + printer->Print( + " };\n" + " static GPBMessageEnumDescription enums[] = {\n"); + printer->Indent(); + printer->Indent(); + printer->Indent(); + for (vector<EnumGenerator*>::iterator iter = enum_generators_.begin(); + iter != enum_generators_.end(); ++iter) { + printer->Print("{ .enumDescriptorFunc = $name$_EnumDescriptor },\n", + "name", (*iter)->name()); + } + printer->Outdent(); + printer->Outdent(); + printer->Outdent(); + } + + bool has_extensions = sorted_extensions.size(); + if (has_extensions) { + printer->Print( + " };\n" + " static GPBExtensionRange ranges[] = {\n"); + printer->Indent(); + printer->Indent(); + printer->Indent(); + for (int i = 0; i < sorted_extensions.size(); i++) { + printer->Print("{ .start = $start$, .end = $end$ },\n", + "start", SimpleItoa(sorted_extensions[i]->start), + "end", SimpleItoa(sorted_extensions[i]->end)); + } + printer->Outdent(); + printer->Outdent(); + printer->Outdent(); + } + + map<string, string> vars; + vars["classname"] = class_name_; + vars["rootclassname"] = root_classname_; + vars["oneofs"] = has_oneofs ? "oneofs" : "NULL"; + vars["oneof_count"] = + has_oneofs ? "sizeof(oneofs) / sizeof(GPBMessageOneofDescription)" : "0"; + vars["enums"] = has_enums ? "enums" : "NULL"; + vars["enum_count"] = + has_enums ? "sizeof(enums) / sizeof(GPBMessageEnumDescription)" : "0"; + vars["ranges"] = has_extensions ? "ranges" : "NULL"; + vars["range_count"] = + has_extensions ? "sizeof(ranges) / sizeof(GPBExtensionRange)" : "0"; + vars["wireformat"] = + descriptor_->options().message_set_wire_format() ? "YES" : "NO"; + + printer->Print(" };\n"); + if (text_format_decode_data.num_entries() == 0) { + printer->Print( + vars, + " descriptor = [GPBDescriptor allocDescriptorForClass:[$classname$ class]\n" + " rootClass:[$rootclassname$ class]\n" + " file:$rootclassname$_FileDescriptor()\n" + " fields:fields\n" + " fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)\n" + " oneofs:$oneofs$\n" + " oneofCount:$oneof_count$\n" + " enums:$enums$\n" + " enumCount:$enum_count$\n" + " ranges:$ranges$\n" + " rangeCount:$range_count$\n" + " storageSize:sizeof($classname$_Storage)\n" + " wireFormat:$wireformat$];\n"); + } else { + vars["extraTextFormatInfo"] = CEscape(text_format_decode_data.Data()); + printer->Print( + vars, + "#if GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n" + " const char *extraTextFormatInfo = NULL;\n" + "#else\n" + " static const char *extraTextFormatInfo = \"$extraTextFormatInfo$\";\n" + "#endif // GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n" + " descriptor = [GPBDescriptor allocDescriptorForClass:[$classname$ class]\n" + " rootClass:[$rootclassname$ class]\n" + " file:$rootclassname$_FileDescriptor()\n" + " fields:fields\n" + " fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)\n" + " oneofs:$oneofs$\n" + " oneofCount:$oneof_count$\n" + " enums:$enums$\n" + " enumCount:$enum_count$\n" + " ranges:$ranges$\n" + " rangeCount:$range_count$\n" + " storageSize:sizeof($classname$_Storage)\n" + " wireFormat:$wireformat$\n" + " extraTextFormatInfo:extraTextFormatInfo];\n"); + } + printer->Print( + " }\n" + " return descriptor;\n" + "}\n\n" + "@end\n\n"); + + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(descriptor_->field(i)) + .GenerateCFunctionImplementations(printer); + } + + for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin(); + iter != oneof_generators_.end(); ++iter) { + (*iter)->GenerateClearFunctionImplementation(printer); + } + } + + for (vector<EnumGenerator*>::iterator iter = enum_generators_.begin(); + iter != enum_generators_.end(); ++iter) { + (*iter)->GenerateSource(printer); + } + + for (vector<MessageGenerator*>::iterator iter = + nested_message_generators_.begin(); + iter != nested_message_generators_.end(); ++iter) { + (*iter)->GenerateSource(printer); + } +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.h b/src/google/protobuf/compiler/objectivec/objectivec_message.h new file mode 100644 index 00000000..5992d0cf --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_message.h @@ -0,0 +1,103 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_H__ + +#include <string> +#include <set> +#include <vector> +#include <google/protobuf/compiler/objectivec/objectivec_field.h> +#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> +#include <google/protobuf/compiler/objectivec/objectivec_oneof.h> +#include <google/protobuf/stubs/common.h> + +namespace google { +namespace protobuf { + +namespace io { +class Printer; // printer.h +} // namespace io + +namespace compiler { +namespace objectivec { + +class ExtensionGenerator; +class EnumGenerator; + +class MessageGenerator { + public: + MessageGenerator(const string& root_classname, const Descriptor* descriptor); + ~MessageGenerator(); + + void GenerateStaticVariablesInitialization(io::Printer* printer, + bool* out_generated); + void GenerateEnumHeader(io::Printer* printer); + void GenerateMessageHeader(io::Printer* printer); + void GenerateSource(io::Printer* printer); + void GenerateExtensionRegistrationSource(io::Printer* printer); + void DetermineDependencies(set<string>* dependencies); + + // This only speaks for this message, not sub message/enums. + bool IsFiltered() const { return filter_reason_.length() > 0; } + // This message being filtered doesn't effect this, instead it covers if + // there are any nested messages or enums. + bool IsSubContentFiltered() const { return sub_content_filtered_; } + + private: + void GenerateParseFromMethodsHeader(io::Printer* printer); + + void GenerateSerializeOneFieldSource(io::Printer* printer, + const FieldDescriptor* field); + void GenerateSerializeOneExtensionRangeSource( + io::Printer* printer, const Descriptor::ExtensionRange* range); + + void GenerateMessageDescriptionSource(io::Printer* printer); + void GenerateDescriptionOneFieldSource(io::Printer* printer, + const FieldDescriptor* field); + + const string root_classname_; + const Descriptor* descriptor_; + FieldGeneratorMap field_generators_; + const string class_name_; + string filter_reason_; + bool sub_content_filtered_; + vector<ExtensionGenerator*> extension_generators_; + vector<EnumGenerator*> enum_generators_; + vector<MessageGenerator*> nested_message_generators_; + vector<OneofGenerator*> oneof_generators_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator); +}; +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_H__ diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc new file mode 100644 index 00000000..9c4a4e44 --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc @@ -0,0 +1,90 @@ +// 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. + +#include <map> +#include <string> + +#include <google/protobuf/compiler/objectivec/objectivec_message_field.h> +#include <google/protobuf/compiler/objectivec/objectivec_helpers.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 objectivec { + +namespace { + +void SetMessageVariables(const FieldDescriptor* descriptor, + map<string, string>* variables) { + const string& message_type = ClassName(descriptor->message_type()); + (*variables)["type"] = message_type; + (*variables)["containing_class"] = ClassName(descriptor->containing_type()); + (*variables)["storage_type"] = message_type; + (*variables)["group_or_message"] = + (descriptor->type() == FieldDescriptor::TYPE_GROUP) ? "Group" : "Message"; + + (*variables)["typeSpecific_value"] = "GPBStringifySymbol(" + message_type + ")"; +} + +} // namespace + +MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor) + : ObjCObjFieldGenerator(descriptor) { + SetMessageVariables(descriptor, &variables_); +} + +MessageFieldGenerator::~MessageFieldGenerator() {} + +bool MessageFieldGenerator::WantsHasProperty(void) const { + if (descriptor_->containing_oneof() != NULL) { + // If in a oneof, it uses the oneofcase instead of a has bit. + return false; + } + // In both proto2 & proto3, message fields have a has* property to tell + // when it is a non default value. + return true; +} + +RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator( + const FieldDescriptor* descriptor) + : RepeatedFieldGenerator(descriptor) { + SetMessageVariables(descriptor, &variables_); + variables_["array_storage_type"] = "NSMutableArray"; +} + +RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message_field.h b/src/google/protobuf/compiler/objectivec/objectivec_message_field.h new file mode 100644 index 00000000..a1ac2d39 --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_message_field.h @@ -0,0 +1,71 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_FIELD_H__ + +#include <map> +#include <string> +#include <google/protobuf/compiler/objectivec/objectivec_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +class MessageFieldGenerator : public ObjCObjFieldGenerator { + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + + protected: + MessageFieldGenerator(const FieldDescriptor* descriptor); + virtual ~MessageFieldGenerator(); + virtual bool WantsHasProperty(void) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator); +}; + +class RepeatedMessageFieldGenerator : public RepeatedFieldGenerator { + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + + protected: + RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor); + virtual ~RepeatedMessageFieldGenerator(); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator); +}; + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_FIELD_H__ diff --git a/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc b/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc new file mode 100644 index 00000000..77664c68 --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc @@ -0,0 +1,139 @@ +// 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. + +#include <map> +#include <string> + +#include <google/protobuf/compiler/objectivec/objectivec_oneof.h> +#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +OneofGenerator::OneofGenerator(const OneofDescriptor* descriptor) + : descriptor_(descriptor) { + variables_["enum_name"] = OneofEnumName(descriptor_); + variables_["name"] = OneofName(descriptor_); + variables_["capitalized_name"] = OneofNameCapitalized(descriptor_); + variables_["raw_index"] = SimpleItoa(descriptor_->index()); + const Descriptor* msg_descriptor = descriptor_->containing_type(); + variables_["owning_message_class"] = ClassName(msg_descriptor); + + string comments; + SourceLocation location; + if (descriptor_->GetSourceLocation(&location)) { + comments = BuildCommentsString(location); + } else { + comments = ""; + } + variables_["comments"] = comments; +} + +OneofGenerator::~OneofGenerator() {} + +void OneofGenerator::SetOneofIndexBase(int index_base) { + int index = descriptor_->index() + index_base; + // Flip the sign to mark it as a oneof. + variables_["index"] = SimpleItoa(-index); +} + +void OneofGenerator::GenerateCaseEnum(io::Printer* printer) { + printer->Print( + variables_, + "typedef GPB_ENUM($enum_name$) {\n"); + printer->Indent(); + printer->Print( + variables_, + "$enum_name$_GPBUnsetOneOfCase = 0,\n"); + string enum_name = variables_["enum_name"]; + for (int j = 0; j < descriptor_->field_count(); j++) { + const FieldDescriptor* field = descriptor_->field(j); + string field_name = FieldNameCapitalized(field); + printer->Print( + "$enum_name$_$field_name$ = $field_number$,\n", + "enum_name", enum_name, + "field_name", field_name, + "field_number", SimpleItoa(field->number())); + } + printer->Outdent(); + printer->Print( + "};\n" + "\n"); +} + +void OneofGenerator::GeneratePublicCasePropertyDeclaration( + io::Printer* printer) { + printer->Print( + variables_, + "$comments$" + "@property(nonatomic, readonly) $enum_name$ $name$OneOfCase;\n" + "\n"); +} + +void OneofGenerator::GenerateClearFunctionDeclaration(io::Printer* printer) { + printer->Print( + variables_, + "void $owning_message_class$_Clear$capitalized_name$OneOfCase($owning_message_class$ *message);\n"); +} + +void OneofGenerator::GeneratePropertyImplementation(io::Printer* printer) { + printer->Print( + variables_, + "@dynamic $name$OneOfCase;\n"); +} + +void OneofGenerator::GenerateClearFunctionImplementation(io::Printer* printer) { + printer->Print( + variables_, + "void $owning_message_class$_Clear$capitalized_name$OneOfCase($owning_message_class$ *message) {\n" + " GPBDescriptor *descriptor = [message descriptor];\n" + " GPBOneofDescriptor *oneof = descriptor->oneofs_[$raw_index$];\n" + " GPBMaybeClearOneof(message, oneof, 0);\n" + "}\n"); +} + +void OneofGenerator::GenerateDescription(io::Printer* printer) { + printer->Print( + variables_, + "{\n" + " .name = \"$name$\",\n" + " .index = $index$,\n" + "},\n"); +} + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/objectivec/objectivec_oneof.h b/src/google/protobuf/compiler/objectivec/objectivec_oneof.h new file mode 100644 index 00000000..77b7f800 --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_oneof.h @@ -0,0 +1,77 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ONEOF_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ONEOF_H__ + +#include <string> +#include <set> +#include <vector> +#include <google/protobuf/descriptor.h> + +namespace google { +namespace protobuf { +namespace io { +class Printer; // printer.h +} +} + +namespace protobuf { +namespace compiler { +namespace objectivec { + +class OneofGenerator { + public: + OneofGenerator(const OneofDescriptor* descriptor); + ~OneofGenerator(); + + void SetOneofIndexBase(int index_base); + + void GenerateCaseEnum(io::Printer* printer); + + void GeneratePublicCasePropertyDeclaration(io::Printer* printer); + void GenerateClearFunctionDeclaration(io::Printer* printer); + + void GeneratePropertyImplementation(io::Printer* printer); + void GenerateClearFunctionImplementation(io::Printer* printer); + void GenerateDescription(io::Printer* printer); + + private: + const OneofDescriptor* descriptor_; + map<string, string> variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OneofGenerator); +}; + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ONEOF_H__ diff --git a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc new file mode 100644 index 00000000..8272c67b --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc @@ -0,0 +1,162 @@ +// 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. + +#include <map> +#include <string> + +#include <google/protobuf/compiler/objectivec/objectivec_primitive_field.h> +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/compiler/objectivec/objectivec_helpers.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/wire_format.h> +#include <google/protobuf/wire_format_lite_inl.h> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/substitute.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +using internal::WireFormat; +using internal::WireFormatLite; + +namespace { + +const char* PrimitiveTypeName(const FieldDescriptor* descriptor) { + ObjectiveCType type = GetObjectiveCType(descriptor); + switch (type) { + case OBJECTIVECTYPE_INT32: + return "int32_t"; + case OBJECTIVECTYPE_UINT32: + return "uint32_t"; + case OBJECTIVECTYPE_INT64: + return "int64_t"; + case OBJECTIVECTYPE_UINT64: + return "uint64_t"; + case OBJECTIVECTYPE_FLOAT: + return "float"; + case OBJECTIVECTYPE_DOUBLE: + return "double"; + case OBJECTIVECTYPE_BOOLEAN: + return "BOOL"; + case OBJECTIVECTYPE_STRING: + return "NSString"; + case OBJECTIVECTYPE_DATA: + return "NSData"; + case OBJECTIVECTYPE_ENUM: + return "int32_t"; + case OBJECTIVECTYPE_MESSAGE: + return NULL; + } +} + +const char* PrimitiveArrayTypeName(const FieldDescriptor* descriptor) { + ObjectiveCType type = GetObjectiveCType(descriptor); + switch (type) { + case OBJECTIVECTYPE_INT32: + return "Int32"; + case OBJECTIVECTYPE_UINT32: + return "UInt32"; + case OBJECTIVECTYPE_INT64: + return "Int64"; + case OBJECTIVECTYPE_UINT64: + return "UInt64"; + case OBJECTIVECTYPE_FLOAT: + return "Float"; + case OBJECTIVECTYPE_DOUBLE: + return "Double"; + case OBJECTIVECTYPE_BOOLEAN: + return "Bool"; + case OBJECTIVECTYPE_STRING: + return ""; // Want NSArray + case OBJECTIVECTYPE_DATA: + return ""; // Want NSArray + case OBJECTIVECTYPE_ENUM: + return "Enum"; + case OBJECTIVECTYPE_MESSAGE: + return ""; // Want NSArray + } +} + +void SetPrimitiveVariables(const FieldDescriptor* descriptor, + map<string, string>* variables) { + std::string primitive_name = PrimitiveTypeName(descriptor); + (*variables)["type"] = primitive_name; + (*variables)["storage_type"] = primitive_name; +} + +} // namespace + +PrimitiveFieldGenerator::PrimitiveFieldGenerator( + const FieldDescriptor* descriptor) + : SingleFieldGenerator(descriptor) { + SetPrimitiveVariables(descriptor, &variables_); +} + +PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} + +PrimitiveObjFieldGenerator::PrimitiveObjFieldGenerator( + const FieldDescriptor* descriptor) + : ObjCObjFieldGenerator(descriptor) { + SetPrimitiveVariables(descriptor, &variables_); + variables_["property_storage_attribute"] = "copy"; +} + +PrimitiveObjFieldGenerator::~PrimitiveObjFieldGenerator() {} + +RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator( + const FieldDescriptor* descriptor) + : RepeatedFieldGenerator(descriptor) { + SetPrimitiveVariables(descriptor, &variables_); + + string base_name = PrimitiveArrayTypeName(descriptor); + if (base_name.length()) { + variables_["array_storage_type"] = "GPB" + base_name + "Array"; + } else { + variables_["array_storage_type"] = "NSMutableArray"; + } +} + +RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} + +void RepeatedPrimitiveFieldGenerator::FinishInitialization(void) { + RepeatedFieldGenerator::FinishInitialization(); + if (IsPrimitiveType(descriptor_)) { + // No comment needed for primitive types. + variables_["array_comment"] = ""; + } +} + + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h new file mode 100644 index 00000000..b3599297 --- /dev/null +++ b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h @@ -0,0 +1,82 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_PRIMITIVE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_PRIMITIVE_FIELD_H__ + +#include <map> +#include <string> +#include <google/protobuf/compiler/objectivec/objectivec_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace objectivec { + +class PrimitiveFieldGenerator : public SingleFieldGenerator { + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + + protected: + PrimitiveFieldGenerator(const FieldDescriptor* descriptor); + virtual ~PrimitiveFieldGenerator(); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator); +}; + +class PrimitiveObjFieldGenerator : public ObjCObjFieldGenerator { + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + + protected: + PrimitiveObjFieldGenerator(const FieldDescriptor* descriptor); + virtual ~PrimitiveObjFieldGenerator(); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveObjFieldGenerator); +}; + +class RepeatedPrimitiveFieldGenerator : public RepeatedFieldGenerator { + friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field); + + protected: + RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor); + virtual ~RepeatedPrimitiveFieldGenerator(); + virtual void FinishInitialization(void); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator); +}; + +} // namespace objectivec +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_PRIMITIVE_FIELD_H__ diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h index 0e264f54..c0a48cea 100644 --- a/src/google/protobuf/descriptor.h +++ b/src/google/protobuf/descriptor.h @@ -59,6 +59,10 @@ #include <vector> #include <google/protobuf/stubs/common.h> +// TYPE_BOOL is defined in the MacOS's ConditionalMacros.h. +#ifdef TYPE_BOOL +#undef TYPE_BOOL +#endif // TYPE_BOOL namespace google { namespace protobuf { diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index d7100370..5ae36510 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -719,9 +719,9 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { "path\030\001 \003(\005B\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030\n\020lead" "ing_comments\030\003 \001(\t\022\031\n\021trailing_comments\030" "\004 \001(\t\022!\n\031leading_detached_comments\030\006 \003(\t" - "BS\n\023com.google.protobufB\020DescriptorProto" - "sH\001\252\002\'Google.ProtocolBuffers.DescriptorP" - "rotos", 4685); + "BY\n\023com.google.protobufB\020DescriptorProto" + "sH\001\242\002\003GPB\252\002\'Google.ProtocolBuffers.Descr" + "iptorProtos", 4691); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/descriptor.proto", &protobuf_RegisterTypes); FileDescriptorSet::default_instance_ = new FileDescriptorSet(); diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto index 375814c9..7099135d 100644 --- a/src/google/protobuf/descriptor.proto +++ b/src/google/protobuf/descriptor.proto @@ -43,6 +43,7 @@ package google.protobuf; option java_package = "com.google.protobuf"; option java_outer_classname = "DescriptorProtos"; option csharp_namespace = "Google.ProtocolBuffers.DescriptorProtos"; +option objc_class_prefix = "GPB"; // descriptor.proto must be optimized for speed because reflection-based // algorithms don't work during bootstrapping. diff --git a/src/google/protobuf/duration.proto b/src/google/protobuf/duration.proto index 59420cc0..0ab970d3 100644 --- a/src/google/protobuf/duration.proto +++ b/src/google/protobuf/duration.proto @@ -44,7 +44,7 @@ option csharp_namespace = "Google.ProtocolBuffers"; // two Timestamp values is a Duration and it can be added or subtracted // from a Timestamp. Range is approximately +-10,000 years. // -// Example 1: compute Duration from two Timestamps in pseudo code. +// Example 1: Compute Duration from two Timestamps in pseudo code. // // Timestamp start = ...; // Timestamp end = ...; @@ -61,7 +61,7 @@ option csharp_namespace = "Google.ProtocolBuffers"; // duration.nanos += 1000000000; // } // -// Example 2: compute Timestamp from Timestamp + Duration in pseudo code. +// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. // // Timestamp start = ...; // Duration duration = ...; @@ -85,9 +85,9 @@ message Duration { // Signed fractions of a second at nanosecond resolution of the span // of time. Durations less than one second are represented with a 0 - // seconds field and a positive or negative nanos field. For durations - // of one second or more, a non-zero value for the nanos field must be - // of the same sign as the seconds field. Must be from -999,999,999 + // `seconds` field and a positive or negative `nanos` field. For durations + // of one second or more, a non-zero value for the `nanos` field must be + // of the same sign as the `seconds` field. Must be from -999,999,999 // to +999,999,999 inclusive. int32 nanos = 2; } diff --git a/src/google/protobuf/empty.proto b/src/google/protobuf/empty.proto new file mode 100644 index 00000000..94df0397 --- /dev/null +++ b/src/google/protobuf/empty.proto @@ -0,0 +1,50 @@ +// 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 google.protobuf; + +option java_multiple_files = true; +option java_outer_classname = "EmptyProto"; +option java_package = "com.google.protobuf"; +option objc_class_prefix = "GPB"; + + +// A generic empty message that you can re-use to avoid defining duplicated +// empty messages in your APIs. A typical example is to use it as the request +// or the response type of an API method. For instance: +// +// service Foo { +// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); +// } +// +message Empty { + +} diff --git a/src/google/protobuf/field_mask.proto b/src/google/protobuf/field_mask.proto index 0b98411c..35b1acc3 100644 --- a/src/google/protobuf/field_mask.proto +++ b/src/google/protobuf/field_mask.proto @@ -35,6 +35,8 @@ option java_multiple_files = true; option java_outer_classname = "FieldMaskProto"; option java_package = "com.google.protobuf"; option csharp_namespace = "Google.ProtocolBuffers"; +option objc_class_prefix = "GPB"; + // `FieldMask` represents a set of symbolic field paths, for example: // diff --git a/src/google/protobuf/preserve_unknown_enum_test.cc b/src/google/protobuf/preserve_unknown_enum_test.cc index 9f8703ae..1673e8af 100644 --- a/src/google/protobuf/preserve_unknown_enum_test.cc +++ b/src/google/protobuf/preserve_unknown_enum_test.cc @@ -246,8 +246,6 @@ TEST(PreserveUnknownEnumTest, Proto2CatchesUnknownValues) { protobuf_unittest::TestAllTypes message; // proto2 message const google::protobuf::Reflection* r = message.GetReflection(); const google::protobuf::Descriptor* d = message.GetDescriptor(); - const google::protobuf::FieldDescriptor* singular_field = - d->FindFieldByName("optional_nested_enum"); const google::protobuf::FieldDescriptor* repeated_field = d->FindFieldByName("repeated_nested_enum"); // Add one element to the repeated field so that we can test @@ -258,6 +256,8 @@ TEST(PreserveUnknownEnumTest, Proto2CatchesUnknownValues) { r->AddEnum(&message, repeated_field, enum_value); #ifdef PROTOBUF_HAS_DEATH_TEST + const google::protobuf::FieldDescriptor* singular_field = + d->FindFieldByName("optional_nested_enum"); // Enum-field integer-based setters GOOGLE_DCHECK-fail on invalid values, in order to // remain consistent with proto2 generated code. EXPECT_DEBUG_DEATH({ diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h index f5f5d3f4..7bfdc40a 100644 --- a/src/google/protobuf/repeated_field.h +++ b/src/google/protobuf/repeated_field.h @@ -626,7 +626,7 @@ DEFINE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(inline, MessageLite); DECLARE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(Message); -#undef DECLARE_SPECIALIZATIONS_FOR_BASE_CLASSES +#undef DECLARE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES template <> inline const MessageLite& GenericTypeHandler<MessageLite>::default_instance() { diff --git a/src/google/protobuf/source_context.proto b/src/google/protobuf/source_context.proto new file mode 100644 index 00000000..2c8a17a8 --- /dev/null +++ b/src/google/protobuf/source_context.proto @@ -0,0 +1,46 @@ +// 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 google.protobuf; + +option java_multiple_files = true; +option java_outer_classname = "SourceContextProto"; +option java_package = "com.google.protobuf"; +option objc_class_prefix = "GPB"; + + +// `SourceContext` represents information about the source of a +// protobuf element, like the file in which it is defined. +message SourceContext { + // The path-qualified name of the .proto file that contained the associated + // protobuf element. For example: `"google/protobuf/source.proto"`. + string file_name = 1; +} diff --git a/src/google/protobuf/struct.proto b/src/google/protobuf/struct.proto index cfe010c2..cd102731 100644 --- a/src/google/protobuf/struct.proto +++ b/src/google/protobuf/struct.proto @@ -36,6 +36,8 @@ option java_multiple_files = true; option java_outer_classname = "StructProto"; option java_package = "com.google.protobuf"; option csharp_namespace = "Google.ProtocolBuffers"; +option objc_class_prefix = "GPB"; + // `Struct` represents a structured data value, consisting of fields // which map to dynamically typed values. In some languages, `Struct` @@ -56,28 +58,33 @@ message Value { oneof kind { // Represents a null value. NullValue null_value = 1; + // Represents a double value. double number_value = 2; + // Represents a string value. string string_value = 3; + // Represents a boolean value. bool bool_value = 4; + // Represents a structured value. Struct struct_value = 5; + // Represents a repeated `Value`. ListValue list_value = 6; } } +// `ListValue` is a wrapper around a repeated field of values. +message ListValue { + // Repeated field of dynamically typed values. + repeated Value values = 1; +} + // `NullValue` is a singleton enumeration to represent the null // value for the `Value` type union. enum NullValue { // Null value. NULL_VALUE = 0; } - -// `ListValue` is a wrapper around a repeated field of values. -message ListValue { - // Repeated field of dynamically typed values. - repeated Value values = 1; -} diff --git a/src/google/protobuf/stubs/atomicops_internals_pnacl.h b/src/google/protobuf/stubs/atomicops_internals_pnacl.h index b10ac02c..3b314fd0 100644 --- a/src/google/protobuf/stubs/atomicops_internals_pnacl.h +++ b/src/google/protobuf/stubs/atomicops_internals_pnacl.h @@ -33,39 +33,197 @@ #ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_ #define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_ +#include <atomic> + namespace google { namespace protobuf { namespace internal { +// This implementation is transitional and maintains the original API for +// atomicops.h. This requires casting memory locations to the atomic types, and +// assumes that the API and the C++11 implementation are layout-compatible, +// which isn't true for all implementations or hardware platforms. The static +// assertion should detect this issue, were it to fire then this header +// shouldn't be used. +// +// TODO(jfb) If this header manages to stay committed then the API should be +// modified, and all call sites updated. +typedef volatile std::atomic<Atomic32>* AtomicLocation32; +static_assert(sizeof(*(AtomicLocation32) nullptr) == sizeof(Atomic32), + "incompatible 32-bit atomic layout"); + +inline void MemoryBarrier() { +#if defined(__GLIBCXX__) + // Work around libstdc++ bug 51038 where atomic_thread_fence was declared but + // not defined, leading to the linker complaining about undefined references. + __atomic_thread_fence(std::memory_order_seq_cst); +#else + std::atomic_thread_fence(std::memory_order_seq_cst); +#endif +} + inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, Atomic32 new_value) { - return __sync_val_compare_and_swap(ptr, old_value, new_value); + ((AtomicLocation32)ptr) + ->compare_exchange_strong(old_value, + new_value, + std::memory_order_relaxed, + std::memory_order_relaxed); + return old_value; } -inline void MemoryBarrier() { - __sync_synchronize(); +inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, + Atomic32 new_value) { + return ((AtomicLocation32)ptr) + ->exchange(new_value, std::memory_order_relaxed); +} + +inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, + Atomic32 increment) { + return increment + + ((AtomicLocation32)ptr) + ->fetch_add(increment, std::memory_order_relaxed); +} + +inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, + Atomic32 increment) { + return increment + ((AtomicLocation32)ptr)->fetch_add(increment); } inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, Atomic32 new_value) { - Atomic32 ret = NoBarrier_CompareAndSwap(ptr, old_value, new_value); + ((AtomicLocation32)ptr) + ->compare_exchange_strong(old_value, + new_value, + std::memory_order_acquire, + std::memory_order_acquire); + return old_value; +} + +inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + ((AtomicLocation32)ptr) + ->compare_exchange_strong(old_value, + new_value, + std::memory_order_release, + std::memory_order_relaxed); + return old_value; +} + +inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) { + ((AtomicLocation32)ptr)->store(value, std::memory_order_relaxed); +} + +inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { + ((AtomicLocation32)ptr)->store(value, std::memory_order_relaxed); MemoryBarrier(); - return ret; } inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { - MemoryBarrier(); - *ptr = value; + ((AtomicLocation32)ptr)->store(value, std::memory_order_release); +} + +inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { + return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed); } inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { - Atomic32 value = *ptr; + return ((AtomicLocation32)ptr)->load(std::memory_order_acquire); +} + +inline Atomic32 Release_Load(volatile const Atomic32* ptr) { + MemoryBarrier(); + return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed); +} + +#if defined(GOOGLE_PROTOBUF_ARCH_64_BIT) + +typedef volatile std::atomic<Atomic64>* AtomicLocation64; +static_assert(sizeof(*(AtomicLocation64) nullptr) == sizeof(Atomic64), + "incompatible 64-bit atomic layout"); + +inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value) { + ((AtomicLocation64)ptr) + ->compare_exchange_strong(old_value, + new_value, + std::memory_order_relaxed, + std::memory_order_relaxed); + return old_value; +} + +inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, + Atomic64 new_value) { + return ((AtomicLocation64)ptr) + ->exchange(new_value, std::memory_order_relaxed); +} + +inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, + Atomic64 increment) { + return increment + + ((AtomicLocation64)ptr) + ->fetch_add(increment, std::memory_order_relaxed); +} + +inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, + Atomic64 increment) { + return increment + ((AtomicLocation64)ptr)->fetch_add(increment); +} + +inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value) { + ((AtomicLocation64)ptr) + ->compare_exchange_strong(old_value, + new_value, + std::memory_order_acquire, + std::memory_order_acquire); + return old_value; +} + +inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value) { + ((AtomicLocation64)ptr) + ->compare_exchange_strong(old_value, + new_value, + std::memory_order_release, + std::memory_order_relaxed); + return old_value; +} + +inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) { + ((AtomicLocation64)ptr)->store(value, std::memory_order_relaxed); +} + +inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) { + ((AtomicLocation64)ptr)->store(value, std::memory_order_relaxed); MemoryBarrier(); - return value; } +inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) { + ((AtomicLocation64)ptr)->store(value, std::memory_order_release); +} + +inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) { + return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed); +} + +inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) { + return ((AtomicLocation64)ptr)->load(std::memory_order_acquire); +} + +inline Atomic64 Release_Load(volatile const Atomic64* ptr) { + MemoryBarrier(); + return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed); +} + +#endif // defined(GOOGLE_PROTOBUF_ARCH_64_BIT) + } // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h index c3f735a2..37123c7b 100644 --- a/src/google/protobuf/stubs/common.h +++ b/src/google/protobuf/stubs/common.h @@ -62,6 +62,14 @@ #include <exception> #endif +#if defined(__APPLE__) +#include <TargetConditionals.h> // for TARGET_OS_IPHONE +#endif + +#if defined(__ANDROID__) || defined(GOOGLE_PROTOBUF_OS_ANDROID) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || defined(GOOGLE_PROTOBUF_OS_IPHONE) +#include <pthread.h> +#endif + #if defined(_WIN32) && defined(GetMessage) // Allow GetMessage to be used as a valid method name in protobuf classes. // windows.h defines GetMessage() as a macro. Let's re-define it as an inline @@ -157,7 +165,7 @@ std::string LIBPROTOBUF_EXPORT VersionString(int version); typedef unsigned int uint; #ifdef _MSC_VER -typedef __int8 int8; +typedef signed __int8 int8; typedef __int16 int16; typedef __int32 int32; typedef __int64 int64; @@ -1158,6 +1166,38 @@ class LIBPROTOBUF_EXPORT MutexLockMaybe { GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLockMaybe); }; +#if defined(__ANDROID__) || defined(GOOGLE_PROTOBUF_OS_ANDROID) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || defined(GOOGLE_PROTOBUF_OS_IPHONE) +// Android ndk does not support the __thread keyword very well yet. Here +// we use pthread_key_create()/pthread_getspecific()/... methods for +// TLS support on android. +// iOS also does not support the __thread keyword. +template<typename T> +class ThreadLocalStorage { + public: + ThreadLocalStorage() { + pthread_key_create(&key_, &ThreadLocalStorage::Delete); + } + ~ThreadLocalStorage() { + pthread_key_delete(key_); + } + T* Get() { + T* result = static_cast<T*>(pthread_getspecific(key_)); + if (result == NULL) { + result = new T(); + pthread_setspecific(key_, result); + } + return result; + } + private: + static void Delete(void* value) { + delete static_cast<T*>(value); + } + pthread_key_t key_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ThreadLocalStorage); +}; +#endif + } // namespace internal // We made these internal so that they would show up as such in the docs, diff --git a/src/google/protobuf/stubs/hash.h b/src/google/protobuf/stubs/hash.h index 82d5052e..11bc2b37 100755 --- a/src/google/protobuf/stubs/hash.h +++ b/src/google/protobuf/stubs/hash.h @@ -172,6 +172,13 @@ struct hash<const char*> { } }; +template<> +struct hash<bool> { + size_t operator()(bool x) const { + return static_cast<size_t>(x); + } +}; + template <typename Key, typename Data, typename HashFcn = hash<Key>, typename EqualKey = std::equal_to<Key>, @@ -204,7 +211,7 @@ struct hash<string> { static const size_t bucket_size = 4; static const size_t min_buckets = 8; - inline size_t operator()(const string& a, const string& b) const { + inline bool operator()(const string& a, const string& b) const { return a < b; } }; @@ -222,7 +229,7 @@ struct hash<pair<First, Second> > { static const size_t bucket_size = 4; static const size_t min_buckets = 8; - inline size_t operator()(const pair<First, Second>& a, + inline bool operator()(const pair<First, Second>& a, const pair<First, Second>& b) const { return a < b; } diff --git a/src/google/protobuf/stubs/platform_macros.h b/src/google/protobuf/stubs/platform_macros.h index 1ff09b83..2ce7fc8f 100644 --- a/src/google/protobuf/stubs/platform_macros.h +++ b/src/google/protobuf/stubs/platform_macros.h @@ -95,12 +95,18 @@ GOOGLE_PROTOBUF_PLATFORM_ERROR #if defined(__APPLE__) #define GOOGLE_PROTOBUF_OS_APPLE +#include <TargetConditionals.h> +#if TARGET_OS_IPHONE +#define GOOGLE_PROTOBUF_OS_IPHONE +#endif #elif defined(__native_client__) #define GOOGLE_PROTOBUF_OS_NACL #elif defined(sun) #define GOOGLE_PROTOBUF_OS_SOLARIS #elif defined(_AIX) #define GOOGLE_PROTOBUF_OS_AIX +#elif defined(__ANDROID__) +#define GOOGLE_PROTOBUF_OS_ANDROID #endif #undef GOOGLE_PROTOBUF_PLATFORM_ERROR diff --git a/src/google/protobuf/stubs/type_traits.h b/src/google/protobuf/stubs/type_traits.h index b58cae3f..36a8f3b1 100644 --- a/src/google/protobuf/stubs/type_traits.h +++ b/src/google/protobuf/stubs/type_traits.h @@ -73,6 +73,10 @@ struct is_base_of { typedef char (&yes)[1]; typedef char (&no)[2]; + // BEGIN GOOGLE LOCAL MODIFICATION -- check is a #define on Mac. + #undef check + // END GOOGLE LOCAL MODIFICATION + static yes check(const B*); static no check(const void*); diff --git a/src/google/protobuf/testing/googletest.cc b/src/google/protobuf/testing/googletest.cc index d72fa5c0..5f6a199a 100644 --- a/src/google/protobuf/testing/googletest.cc +++ b/src/google/protobuf/testing/googletest.cc @@ -65,6 +65,7 @@ namespace protobuf { #endif string TestSourceDir() { +#ifndef GOOGLE_THIRD_PARTY_PROTOBUF #ifdef _MSC_VER // Look for the "src" directory. string prefix = "."; @@ -88,6 +89,9 @@ string TestSourceDir() { return result; } #endif +#else + return "third_party/protobuf/src"; +#endif // GOOGLE_THIRD_PARTY_PROTOBUF } namespace { diff --git a/src/google/protobuf/timestamp.proto b/src/google/protobuf/timestamp.proto index 94386de1..381ff997 100644 --- a/src/google/protobuf/timestamp.proto +++ b/src/google/protobuf/timestamp.proto @@ -36,6 +36,8 @@ option java_multiple_files = true; option java_outer_classname = "TimestampProto"; option java_package = "com.google.protobuf"; option csharp_namespace = "Google.ProtocolBuffers"; +option objc_class_prefix = "GPB"; + // A Timestamp represents a point in time independent of any time zone // or calendar, represented as seconds and fractions of seconds at @@ -46,15 +48,16 @@ option csharp_namespace = "Google.ProtocolBuffers"; // table is needed for interpretation. Range is from // 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. // By restricting to that range, we ensure that we can convert to -// and from RFC 3339 date strings. (See https://www.ietf.org/rfc/rfc3339.txt.) +// and from RFC 3339 date strings. +// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt). // -// Example 1: compute Timestamp from POSIX `time()`. +// Example 1: Compute Timestamp from POSIX `time()`. // // Timestamp timestamp; // timestamp.set_seconds(time(NULL)); // timestamp.set_nanos(0); // -// Example 2: compute Timestamp from POSIX `gettimeofday()`. +// Example 2: Compute Timestamp from POSIX `gettimeofday()`. // // struct timeval tv; // gettimeofday(&tv, NULL); @@ -63,7 +66,7 @@ option csharp_namespace = "Google.ProtocolBuffers"; // timestamp.set_seconds(tv.tv_sec); // timestamp.set_nanos(tv.tv_usec * 1000); // -// Example 3: compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. +// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. // // FILETIME ft; // GetSystemTimeAsFileTime(&ft); @@ -75,14 +78,14 @@ option csharp_namespace = "Google.ProtocolBuffers"; // timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); // timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); // -// Example 4: compute Timestamp from Java `System.currentTimeMillis()`. +// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. // // long millis = System.currentTimeMillis(); // // Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) // .setNanos((int) ((millis % 1000) * 1000000)).build(); // -// Example 5: compute Timestamp from Python `datetime.datetime`. +// Example 5: Compute Timestamp from Python `datetime.datetime`. // // now = datetime.datetime.utcnow() // seconds = int(time.mktime(now.timetuple())) diff --git a/src/google/protobuf/type.proto b/src/google/protobuf/type.proto new file mode 100644 index 00000000..ace5d995 --- /dev/null +++ b/src/google/protobuf/type.proto @@ -0,0 +1,197 @@ +// 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 google.protobuf; + +import "google/protobuf/any.proto"; +import "google/protobuf/source_context.proto"; + +option java_multiple_files = true; +option java_outer_classname = "TypeProto"; +option java_package = "com.google.protobuf"; +option objc_class_prefix = "GPB"; + + +// A light-weight descriptor for a proto message type. +message Type { + // The fully qualified message name. + string name = 1; + + // The list of fields. + repeated Field fields = 2; + + // The list of oneof definitions. + // The list of oneofs declared in this Type + repeated string oneofs = 3; + + // The proto options. + repeated Option options = 4; + + // The source context. + SourceContext source_context = 5; +} + +// Field represents a single field of a message type. +message Field { + // Kind represents a basic field type. + enum Kind { + // Field type unknown. + TYPE_UNKNOWN = 0; + + // Field type double. + TYPE_DOUBLE = 1; + + // Field type float. + TYPE_FLOAT = 2; + + // Field type int64. + TYPE_INT64 = 3; + + // Field type uint64. + TYPE_UINT64 = 4; + + // Field type int32. + TYPE_INT32 = 5; + + // Field type fixed64. + TYPE_FIXED64 = 6; + + // Field type fixed32. + TYPE_FIXED32 = 7; + + // Field type bool. + TYPE_BOOL = 8; + + // Field type string. + TYPE_STRING = 9; + + // Field type message. + TYPE_MESSAGE = 11; + + // Field type bytes. + TYPE_BYTES = 12; + + // Field type uint32. + TYPE_UINT32 = 13; + + // Field type enum. + TYPE_ENUM = 14; + + // Field type sfixed32. + TYPE_SFIXED32 = 15; + + // Field type sfixed64. + TYPE_SFIXED64 = 16; + + // Field type sint32. + TYPE_SINT32 = 17; + + // Field type sint64. + TYPE_SINT64 = 18; + } + + // Cardinality represents whether a field is optional, required, or + // repeated. + enum Cardinality { + // The field cardinality is unknown. Typically an error condition. + CARDINALITY_UNKNOWN = 0; + + // For optional fields. + CARDINALITY_OPTIONAL = 1; + + // For required fields. Not used for proto3. + CARDINALITY_REQUIRED = 2; + + // For repeated fields. + CARDINALITY_REPEATED = 3; + } + + // The field kind. + Kind kind = 1; + + // The field cardinality, i.e. optional/required/repeated. + Cardinality cardinality = 2; + + // The proto field number. + int32 number = 3; + + // The field name. + string name = 4; + + // The type URL (without the scheme) when the type is MESSAGE or ENUM, + // such as `type.googleapis.com/google.protobuf.Empty`. + string type_url = 6; + + // Index in Type.oneofs. Starts at 1. Zero means no oneof mapping. + int32 oneof_index = 7; + + // Whether to use alternative packed wire representation. + bool packed = 8; + + // The proto options. + repeated Option options = 9; +} + +// Enum type definition. +message Enum { + // Enum type name. + string name = 1; + + // Enum value definitions. + repeated EnumValue enumvalue = 2; + + // Proto options for the enum type. + repeated Option options = 3; + + // The source context. + SourceContext source_context = 4; +} + +// Enum value definition. +message EnumValue { + // Enum value name. + string name = 1; + + // Enum value number. + int32 number = 2; + + // Proto options for the enum value. + repeated Option options = 3; +} + +// Proto option attached to messages/fields/enums etc. +message Option { + // Proto option name. + string name = 1; + + // Proto option value. + Any value = 2; +} diff --git a/src/google/protobuf/unittest_drop_unknown_fields.proto b/src/google/protobuf/unittest_drop_unknown_fields.proto index 1bb168f2..1b35fad0 100644 --- a/src/google/protobuf/unittest_drop_unknown_fields.proto +++ b/src/google/protobuf/unittest_drop_unknown_fields.proto @@ -31,6 +31,7 @@ syntax = "proto3"; package unittest_drop_unknown_fields; +option objc_class_prefix = "DropUnknowns"; option csharp_namespace = "Google.ProtocolBuffers.TestProtos"; diff --git a/src/google/protobuf/unittest_preserve_unknown_enum.proto b/src/google/protobuf/unittest_preserve_unknown_enum.proto index 5214247e..24e6828f 100644 --- a/src/google/protobuf/unittest_preserve_unknown_enum.proto +++ b/src/google/protobuf/unittest_preserve_unknown_enum.proto @@ -31,6 +31,7 @@ syntax = "proto3"; package proto3_preserve_unknown_enum_unittest; +option objc_class_prefix = "UnknownEnums"; option csharp_namespace = "Google.ProtocolBuffers.TestProtos"; diff --git a/src/google/protobuf/wrappers.proto b/src/google/protobuf/wrappers.proto index 28657fbf..a13e6edb 100644 --- a/src/google/protobuf/wrappers.proto +++ b/src/google/protobuf/wrappers.proto @@ -41,6 +41,8 @@ option java_multiple_files = true; option java_outer_classname = "WrappersProto"; option java_package = "com.google.protobuf"; option csharp_namespace = "Google.ProtocolBuffers"; +option objc_class_prefix = "GPB"; + // Wrapper message for double. message DoubleValue { |