From d73ccd8070a9cd2309c837317207c75e39342efa Mon Sep 17 00:00:00 2001 From: William Entriken Date: Fri, 6 Dec 2024 05:09:04 -0500 Subject: [PATCH 1/6] Update to work with new Bazel (#599) Co-authored-by: Doug Rinckes --- .bazelrc | 4 ---- MODULE.bazel | 23 ++++++++++++++++++++ WORKSPACE | 56 ------------------------------------------------ c/BUILD | 25 +++++++++++++-------- cpp/BUILD | 24 +++++++++++++++------ cpp/gtest.BUILD | 14 ------------ java/BUILD | 9 ++++++++ js/closure/BUILD | 7 ++++-- python/BUILD | 5 ++--- 9 files changed, 72 insertions(+), 95 deletions(-) create mode 100644 MODULE.bazel delete mode 100644 WORKSPACE delete mode 100644 cpp/gtest.BUILD diff --git a/.bazelrc b/.bazelrc index a138f643..c5923401 100644 --- a/.bazelrc +++ b/.bazelrc @@ -5,9 +5,5 @@ startup --host_jvm_args=-XX:-UseParallelGC # build --local_resources=400,2,1.0 build --worker_max_instances=auto -# Setting to false will cause Bazel to use local JDK. This can cause the -# build to fail if it is not version 9. -build --distinct_host_configuration=true - # Configure tests - increase timeout, print everything and timeout warnings test --verbose_failures --test_output=all --test_verbose_timeout_warnings diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 00000000..a4288ff7 --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,23 @@ +module( + name = "openlocationcode", + version = "1.0", +) + +bazel_dep(name = "googletest", version = "1.15.2") +bazel_dep(name = "rules_proto", version = "6.0.2") # Deprecated (moved), TODO find new URL +bazel_dep(name = "rules_java", version = "7.8.0") +bazel_dep(name = "bazel_skylib", version = "1.6.1") +bazel_dep(name = "rules_python", version = "0.33.2") + +# External dependency archives +http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +http_archive( + name = "io_bazel_rules_closure", + sha256 = "9498e57368efb82b985db1ed426a767cbf1ba0398fd7aed632fc3908654e1b1e", + strip_prefix = "rules_closure-0.12.0", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/rules_closure/archive/0.12.0.tar.gz", + "https://github.com/bazelbuild/rules_closure/archive/0.12.0.tar.gz", + ], +) \ No newline at end of file diff --git a/WORKSPACE b/WORKSPACE deleted file mode 100644 index 5d9cd211..00000000 --- a/WORKSPACE +++ /dev/null @@ -1,56 +0,0 @@ -workspace(name = "openlocationcode") - -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") - -# Include the Google Test framework for C++ testing. -# See https://github.com/google/googletest -http_archive( - name = "gtest", - url = "https://github.com/google/googletest/archive/release-1.8.0.zip", - sha256 = "f3ed3b58511efd272eb074a3a6d6fb79d7c2e6a0e374323d1e6bcbcc1ef141bf", - build_file = "//cpp:gtest.BUILD", - strip_prefix = "googletest-release-1.8.0/googletest", -) - -# Include the Bazel Closure rules for javascript testing.. -# See https://github.com/bazelbuild/rules_closure -# zlib library is required for com_google_protobuf which is loaded by the closure rules. -# skylib library required by closure rules. -# See the Closure WORKSPACE files for the above. -# Closure rules are pulled in at a specific commit because the current release -# (0.8.0) doesn't work with Bazel 0.24.1+. -http_archive( - name = "net_zlib", - # Original build file reference doesn't work. Fails with: - # Unable to load package for //:third_party/zlib.BUILD: not found. and referenced by '//external:zlib' - # build_file = "//:third_party/zlib.BUILD", - build_file = "@com_google_protobuf//:third_party/zlib.BUILD", - sha256 = "c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1", - strip_prefix = "zlib-1.2.11", - urls = [ - "https://mirror.bazel.build/zlib.net/zlib-1.2.11.tar.gz", - "https://zlib.net/zlib-1.2.11.tar.gz", - ], -) -# com_google_protobuf depends on zlib, not net_zlib, so we need to bind. -bind( - name = "zlib", - actual = "@net_zlib//:zlib", -) -http_archive( - name = "bazel_skylib", - sha256 = "bbccf674aa441c266df9894182d80de104cabd19be98be002f6d478aaa31574d", - strip_prefix = "bazel-skylib-2169ae1c374aab4a09aa90e65efe1a3aad4e279b", - urls = ["https://github.com/bazelbuild/bazel-skylib/archive/2169ae1c374aab4a09aa90e65efe1a3aad4e279b.tar.gz"], -) -http_archive( - name = "io_bazel_rules_closure", - sha256 = "1c05fea22c9630cf1047f25d008780756373a60ddd4d2a6993cf9858279c5da6", - strip_prefix = "rules_closure-50d3dc9e6d27a5577a0f95708466718825d579f4", - urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/rules_closure/archive/50d3dc9e6d27a5577a0f95708466718825d579f4.tar.gz", - "https://github.com/bazelbuild/rules_closure/archive/50d3dc9e6d27a5577a0f95708466718825d579f4.tar.gz", - ], -) -load("@io_bazel_rules_closure//closure:defs.bzl", "closure_repositories") -closure_repositories() diff --git a/c/BUILD b/c/BUILD index 6d861123..7a273870 100644 --- a/c/BUILD +++ b/c/BUILD @@ -1,37 +1,43 @@ -# Rule to build the library. cc_library( name = "openlocationcode", srcs = [ "src/olc.c", ], - copts = ["-std=c99"], + copts = [ + "-std=c99", + "-Wall", + "-Wextra", + "-O2", + ], hdrs = [ "src/olc.h", "src/olc_private.h", ], - visibility = ["//visibility:public"], + includes = ["src"], + visibility = ["//visibility:private"], ) -# Rule to build and run the unit tests. cc_test( name = "openlocationcode_test", size = "small", srcs = ["openlocationcode_test.cc"], copts = [ "-pthread", - "-Iexternal/gtest/include", + "-I@googletest//:include", ], + linkopts = ["-pthread"], + linkstatic = False, data = [ "//test_data", ], - linkopts = ["-pthread"], deps = [ ":openlocationcode", - "@gtest//:main", + "@googletest//:gtest_main", ], + testonly = True, + visibility = ["//visibility:private"], ) -# Rule to build and run the example. cc_binary( name = "openlocationcode_example", srcs = [ @@ -40,4 +46,5 @@ cc_binary( deps = [ ":openlocationcode", ], -) + visibility = ["//visibility:private"], +) \ No newline at end of file diff --git a/cpp/BUILD b/cpp/BUILD index d31b6b52..1776e802 100644 --- a/cpp/BUILD +++ b/cpp/BUILD @@ -1,3 +1,4 @@ +# Library to handle open location codes cc_library( name = "openlocationcode", srcs = [ @@ -7,14 +8,19 @@ cc_library( "codearea.h", "openlocationcode.h", ], - copts = ["-pthread"], + copts = [ + "-pthread", + "-Wall", + "-Wextra", + "-O2", + ], linkopts = ["-pthread"], - visibility = ["//visibility:public"], deps = [ ":codearea", ], ) +# Code area library, used by open location codes cc_library( name = "codearea", srcs = [ @@ -23,27 +29,31 @@ cc_library( hdrs = [ "codearea.h", ], - visibility = ["//visibility:private"], + visibility = ["//visibility:private"], # Keep private unless needed elsewhere ) +# Unit test for open location codes cc_test( name = "openlocationcode_test", size = "small", srcs = ["openlocationcode_test.cc"], copts = [ "-pthread", - "-Iexternal/gtest/include", + "-I@googletest//:include", ], + linkopts = ["-pthread"], + linkstatic = False, data = [ "//test_data", ], - linkopts = ["-pthread"], deps = [ ":openlocationcode", - "@gtest//:main", + "@googletest//:gtest_main", ], + testonly = True, ) +# Example binary for open location codes cc_binary( name = "openlocationcode_example", srcs = [ @@ -52,4 +62,4 @@ cc_binary( deps = [ ":openlocationcode", ], -) +) \ No newline at end of file diff --git a/cpp/gtest.BUILD b/cpp/gtest.BUILD deleted file mode 100644 index 528c7813..00000000 --- a/cpp/gtest.BUILD +++ /dev/null @@ -1,14 +0,0 @@ -cc_library( - name = "main", - srcs = glob( - ["src/*.cc"], - exclude = ["src/gtest-all.cc"] - ), - hdrs = glob([ - "include/**/*.h", - "src/*.h" - ]), - copts = ["-Iexternal/gtest/include"], - linkopts = ["-pthread"], - visibility = ["//visibility:public"], -) \ No newline at end of file diff --git a/java/BUILD b/java/BUILD index ad28295f..f36746b5 100644 --- a/java/BUILD +++ b/java/BUILD @@ -3,6 +3,7 @@ java_library( srcs = [ "src/main/java/com/google/openlocationcode/OpenLocationCode.java", ], + visibility = ["//visibility:private"], ) java_test( @@ -15,6 +16,7 @@ java_test( deps = [ ":openlocationcode", ], + visibility = ["//visibility:private"], ) java_test( @@ -31,6 +33,7 @@ java_test( deps = [ ":openlocationcode", ], + visibility = ["//visibility:private"], ) java_test( @@ -47,6 +50,7 @@ java_test( deps = [ ":openlocationcode", ], + visibility = ["//visibility:private"], ) java_test( @@ -63,6 +67,7 @@ java_test( deps = [ ":openlocationcode", ], + visibility = ["//visibility:private"], ) java_test( @@ -79,6 +84,7 @@ java_test( deps = [ ":openlocationcode", ], + visibility = ["//visibility:private"], ) java_test( @@ -92,6 +98,7 @@ java_test( deps = [ ":openlocationcode", ], + visibility = ["//visibility:private"], ) java_test( @@ -105,6 +112,7 @@ java_test( deps = [ ":openlocationcode", ], + visibility = ["//visibility:private"], ) java_test( @@ -118,4 +126,5 @@ java_test( deps = [ ":openlocationcode", ], + visibility = ["//visibility:private"], ) diff --git a/js/closure/BUILD b/js/closure/BUILD index d532699f..74e4183f 100644 --- a/js/closure/BUILD +++ b/js/closure/BUILD @@ -1,17 +1,20 @@ +# Load the necessary Closure rules load("@io_bazel_rules_closure//closure:defs.bzl", "closure_js_library", "closure_js_test") +# Define the Closure library for Open Location Code closure_js_library( name = "openlocationcode_lib", srcs = ["openlocationcode.js"], convention = "GOOGLE", ) +# Define the Closure test for Open Location Code closure_js_test( name = "openlocationcode_test", timeout = "short", srcs = ["openlocationcode_test.js"], data = [ - "//test_data", + "//test_data:test_data", # Reference the filegroup for test data ], entry_points = ["goog:openlocationcode_test"], deps = [ @@ -22,4 +25,4 @@ closure_js_test( "@io_bazel_rules_closure//closure/library/testing:asynctestcase", "@io_bazel_rules_closure//closure/library/testing:testsuite", ], -) +) \ No newline at end of file diff --git a/python/BUILD b/python/BUILD index 8b42e169..5d2f210e 100644 --- a/python/BUILD +++ b/python/BUILD @@ -1,5 +1,3 @@ -package(default_visibility = ["//visibility:public"]) - py_library( name = "openlocationcode", srcs = ["openlocationcode/openlocationcode.py"], @@ -12,4 +10,5 @@ py_test( srcs = ["openlocationcode_test.py"], data = ["//test_data:test_data"], deps = [":openlocationcode"], -) + visibility = ["//visibility:private"] +) \ No newline at end of file From 60b87b1857bfe03e473647510cabe47aaf4efae5 Mon Sep 17 00:00:00 2001 From: Kyle Lee <59222981+kylelmh@users.noreply.github.com> Date: Fri, 6 Dec 2024 19:12:32 +0900 Subject: [PATCH 2/6] migrated dart to v3 (#639) Co-authored-by: Doug Rinckes --- dart/lib/src/open_location_code.dart | 7 ++++++- dart/pubspec.yaml | 4 ++-- dart/test/encode_test.dart | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/dart/lib/src/open_location_code.dart b/dart/lib/src/open_location_code.dart index b8af9cf7..10ecc5ac 100644 --- a/dart/lib/src/open_location_code.dart +++ b/dart/lib/src/open_location_code.dart @@ -134,7 +134,12 @@ bool isValid(String code) { if (padMatch.length != 1) { return false; } - var matchLength = padMatch.first.group(0).length; + var matches = padMatch.first.group(0); + if (matches == null) { + return false; + } + + var matchLength = matches.length; if (matchLength.isOdd || matchLength > separatorPosition - 2) { return false; } diff --git a/dart/pubspec.yaml b/dart/pubspec.yaml index 67c6670d..3fe399a8 100644 --- a/dart/pubspec.yaml +++ b/dart/pubspec.yaml @@ -3,6 +3,6 @@ description: Open Location Codes are short, generated codes that can be used lik version: 0.0.1 homepage: http://openlocationcode.com/ environment: - sdk: '<3.0.0' + sdk: '^2.19.6' dev_dependencies: - test: '>=0.12.0' + test: ^1.24.3 diff --git a/dart/test/encode_test.dart b/dart/test/encode_test.dart index bc71fcfc..154b313d 100644 --- a/dart/test/encode_test.dart +++ b/dart/test/encode_test.dart @@ -23,7 +23,7 @@ void checkEncodeDecode(String csvLine) { var elements = csvLine.split(','); num lat = double.parse(elements[0]); num lng = double.parse(elements[1]); - num len = int.parse(elements[2]); + int len = int.parse(elements[2]); var want = elements[3]; var got = olc.encode(lat, lng, codeLength: len); expect(got, equals(want)); From 6212a78327bb8f2040502654f7ffeebbbd416694 Mon Sep 17 00:00:00 2001 From: Doug Rinckes Date: Fri, 6 Dec 2024 11:15:55 +0100 Subject: [PATCH 3/6] Merge API recommendations and short code guidance into the specification. (#597) --- Documentation/Specification/API.md | 62 ------------ .../Specification/Short_Code_Guidance.md | 22 ----- Documentation/Specification/specification.md | 96 ++++++++++++++++--- 3 files changed, 82 insertions(+), 98 deletions(-) delete mode 100644 Documentation/Specification/API.md delete mode 100644 Documentation/Specification/Short_Code_Guidance.md diff --git a/Documentation/Specification/API.md b/Documentation/Specification/API.md deleted file mode 100644 index eb02c08d..00000000 --- a/Documentation/Specification/API.md +++ /dev/null @@ -1,62 +0,0 @@ -# Open Location Code Reference API - -## Version History - -- Version 1.0.0 / 2014-10-27 / [Doug Rinckes](https://github.com/drinckes), Google / Philipp Bunge, Google - - Initial public release - -## Public methods - -The following public methods should be provided by any Open Location Code implementation, subject to minor changes caused by language conventions. - -Note that any method that returns an Open Location Code should return upper case characters. - -Methods that accept Open Location Codes as parameters should be case insensitive. - -### `isValid` - -The `isValid` method takes a single parameter, a string, and returns a boolean indicating whether the string is a valid Open Location Code sequence or not. - -To be valid, all characters must be from the Open Location Code character set with exactly one separator. -There must be an even number of at most eight characters before the separator. -(Zero characters before the separator is valid.) - -### `isShort` - -The `isShort` method takes a single parameter, a string, and returns a boolean indicating whether the string is a valid short Open Location Code or not. - -A short Open Location Code is a sequence created by removing an even number of characters from a full Open Location Code. -The resulting code must still include the separator character. - -### `isFull` - -Determines if a code is a valid full Open Location Code. - -Not all possible combinations of Open Location Code characters decode to valid latitude and longitude values. -This checks that a code is valid and also that the latitude and longitude values are legal. -Full codes must include the separator character and it must be after eight characters. - -### `encode` - -Encode a location into an Open Location Code. -This takes a latitude and longitude and an optional length. -If the length is not specified, a code with 10 digits and an additional separator character will be generated. - -### `decode` - -Decodes an Open Location Code into the location coordinates. This method takes a string. -If the string is a valid full Open Location Code, it returns an object with the lower and upper latitude and longitude pairs, the center latitude and longitude, and the length of the original code. - -### `shorten` - -Passed a valid full Open Location Code and a latitude and longitude this removes as many digits as possible (up to a maximum of six) such that the resulting code is the closest matching code to the passed location. -A safety factor may be included. - -If the code cannot be shortened, the original full code should be returned. - -Since the only really useful shortenings are removing the first four or six characters, this method may be replaced with methods such as `shortenBy4` or `shortenBy6`. - -### `recoverNearest` - -This method is passed a valid short Open Location Code and a latitude and longitude, and returns the nearest matching full Open Location Code to the specified location. - diff --git a/Documentation/Specification/Short_Code_Guidance.md b/Documentation/Specification/Short_Code_Guidance.md deleted file mode 100644 index 38f6af84..00000000 --- a/Documentation/Specification/Short_Code_Guidance.md +++ /dev/null @@ -1,22 +0,0 @@ -# Short Code Guidance - -Shortening codes is a key feature that aids their usability. - -Being able to say _WF8Q+WF, Praia_ is significantly easier than remembering and using _796RWF8Q+WF_. -With that in mind, how do you choose the locality to use as a reference? - -Ideally, you need to use both the center point and the bounding box. - -Given a global code, _796RWF8Q+WF_, you can eliminate the first **four** digits of the code if: - * The center point of the feature is within **0.4** degrees latitude and **0.4** degrees longitude - * The bounding box of the feature is less than **0.8** degrees high and wide. - -If there is no suitable locality close enough or small enough, you can eliminate the first **two** digits of the code if: - * The center point of the feature is within **8** degrees latitude and **8** degrees longitude - * The bounding box of the feature is less than **16** degrees high and wide. - -These values are are chosen to allow for different geocoder backends placing localities in slightly different positions. -Although they can be slightly increased there will be a risk that a shortened code will recover to a different location than the original, and people misdirected. - -Note: Usually your feature will be a town or city, but you could also use geographical features such as lakes or mountains, if they are the best local reference. -If a settlement (such as neighbourhood, town or city) is to be used, you should choose the most prominent feature that meets the requirements, to avoid using obscure features that may not be widely known. \ No newline at end of file diff --git a/Documentation/Specification/specification.md b/Documentation/Specification/specification.md index bdb43c6b..7a262cf0 100644 --- a/Documentation/Specification/specification.md +++ b/Documentation/Specification/specification.md @@ -2,7 +2,7 @@ ## Input values -Open Location Code encodes two numbers into a single, short string. +Open Location Code encodes two numbers, latitude and longitude, in degrees, into a single, short string. The latitude and longitude should be WGS84 values. If other datums are used it must be stated and made clear that these will produce different locations if plotted. @@ -126,19 +126,87 @@ For example, 8FVC9G8F+6W has the center 47.365562,8.524813. The following table Note: A code that has been shortened will not necessarily have the same initial four digits as the reference location. -## Library Implementation Requirements +### Generating Short Codes -Open Location Code library implementations must provide: -* a method to convert a latitude and longitude into a 10 digit Open Location Code -* a method to decode a 10 digit Open Location Code into, at a minimum, the latitude and longitude of the south-west corner and the height and width -* a method to determine if a string is a valid sequence of Open Location Code characters -* a method to determine if a string is a valid full Open Location Code -* decode and validation methods must not be case-sensitive +Being able to say _WF8Q+WF, Praia_ is significantly easier than remembering and using _796RWF8Q+WF_. +With that in mind, how do you choose the locality to use as a reference? -Open Location Code library implementations can provide: -* a method to convert a latitude and longitude into any valid length Open Location Code -* a method to decode any valid length Open Location Code, providing additional information such as center coordinates -* a method to to convert a valid Open Location Code into a short code, given a reference location -* a method to recover a full Open Location Code from a short code and a reference location. -* a method to determine if a string is a valid short Open Location Code +Ideally, you need to use both the bounding box of the locality, as well as its center point. +Given a global code, _796RWF8Q+WF_, you can eliminate the first **four** digits of the code if: + * The center point of the feature is within **0.4** degrees latitude and **0.4** degrees longitude + * The bounding box of the feature is less than **0.8** degrees high and wide. + +(These values are chosen because a four digit Open Location Code is 1x1 degrees.) + +If there is no suitable locality close enough or small enough, you can eliminate the first **two** digits of the code if: + * The center point of the feature is within **8** degrees latitude and **8** degrees longitude + * The bounding box of the feature is less than **16** degrees high and wide. + +(These values are chosen because a two digit Open Location Code is 20x20 degrees.) + +The values above are slightly smaller than the maximums to allow for different geocoder backends placing localities in slightly different positions. +Although they could be increased there will be a risk that a shortened code will recover to a different location than the original, and people misdirected. + +Note: Usually your feature will be a town or city, but you could also use geographical features such as lakes or mountains, if they are the best local reference. +If a settlement (such as neighbourhood, town or city) is to be used, you should choose the most prominent feature that meets the requirements, to avoid using obscure features that may not be widely known. +(Basically, prefer city or town over neighbourhood.) + +## API Requirements + +The following public methods should be provided by any Open Location Code implementation, subject to minor changes caused by language conventions. + +Note that any method that returns an Open Location Code should return upper case characters. + +Methods that accept Open Location Codes as parameters should be case insensitive. + +Capitalisation should follow the language convention, for example the method `isValid` in golang would be `IsValid`. + +Errors should be returned following the language convention. For example exceptions in Python and Java, `error` objects in golang. + +### `isValid` + +The `isValid` method takes a single parameter, a string, and returns a boolean indicating whether the string is a valid Open Location Code sequence. + +### `isShort` + +The `isShort` method takes a single parameter, a string, and returns a boolean indicating whether the string is a valid short Open Location Code. + + See [Short Codes](#short-codes) above. + +### `isFull` + +Determines if a code is a valid full (i.e. not shortened) Open Location Code. + +Not all possible combinations of Open Location Code characters decode to valid latitude and longitude values. +This checks that a code is valid and that the resulting latitude and longitude values are legal. +Full codes must include the format separator character and it must be after eight characters. + +### `encode` + +Encode a location into an Open Location Code. +This takes a latitude and longitude and an optional length. +If the length is not specified, a code with 10 digits (and the format separator character) will be returned. + +### `decode` + +Decodes an Open Location Code into the location coordinates. +This method takes a string. +If the string is a valid full Open Location Code, it returns: +- the latitude and longitude of the SW corner of the bounding box; +- the latitude and longitude of the NE corner of the bounding box; +- the latitude and longitude of the center of the bounding box; +- the number of digits in the original code. + +### `shorten` + +Passed a valid full Open Location Code and a latitude and longitude this removes as many digits as possible (up to a maximum of six) such that the resulting code is the closest matching code to the passed location. +A safety factor may be included. + +If the code cannot be shortened, the original full code should be returned. + +Since the only really useful shortenings are removing the first four or six characters, methods such as `shortenBy4` or `shortenBy6` could be provided instead. + +### `recoverNearest` + +This method is passed a valid short Open Location Code and a latitude and longitude, and returns the nearest matching full Open Location Code to the specified location. From 4e213e583b77b149a60374859de9b555d7f73617 Mon Sep 17 00:00:00 2001 From: Andreas Date: Fri, 6 Dec 2024 11:40:17 +0100 Subject: [PATCH 4/6] Update Using_Spreadsheets.md (#638) Changing YouTube links from "Plus Codes" to "Google Maps" channel, updating playlist link accordingly. Co-authored-by: Doug Rinckes --- Documentation/Reference/Using_Spreadsheets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/Reference/Using_Spreadsheets.md b/Documentation/Reference/Using_Spreadsheets.md index 51d705a1..24f7cc2b 100644 --- a/Documentation/Reference/Using_Spreadsheets.md +++ b/Documentation/Reference/Using_Spreadsheets.md @@ -8,7 +8,7 @@ This page explains how you can access the Open Location Code functions from Exce There is an [add-on for Google Sheets](https://gsuite.google.com/marketplace/app/plus_codes/604254879289) that allows you to create plus codes from latitude and longitude coordinates, and to decode them as well. -The [plus codes youtube channel](https://www.youtube.com/c/pluscodes) has some [videos showing how to install and use the add-on](https://www.youtube.com/playlist?list=PLaBfOq9xgeeBgOLyKnw8kvpFpZ_9v_sHa). +The [Google Maps YouTube channel](https://www.youtube.com/@googlemaps) has some [videos showing how to install and use the add-on](https://www.youtube.com/playlist?list=PLcRbp4LqBpwE5ofG2MN08D_4DJAk9gZBI). ## Excel/LibreOffice From 5a8c9a01d374858c41926fc3f226675ca5cf7cea Mon Sep 17 00:00:00 2001 From: Will Beason Date: Fri, 6 Dec 2024 04:51:49 -0600 Subject: [PATCH 5/6] Reduce runtime of Encode() by 20% (#566) This is a performance optimization change for Encode(). As-is, Encode() always calls a stringconcat (by "+"-ing strings together). This call is unnecessary as we know the structure of the location codes ahead of time, and non-performant as stringconcat is slow compared to slicebytetostring. To do this, I made the initial byte slice allocated represent the entire final code and immediately fill in the separator. This means later, when we format the code, we don't need to concatenate the Separator in as it is already there. I introduce a special case for the location pair after the separator rather than having those bytes computed in the loop: otherwise we need to have an if-statement within the loop. As a bonus, having these computed first let us to remove the two unnecessary divides that formerly happened at the end of the final loop. (I am unsure if this last point is noticeable - I could not detect a significant difference.) Co-authored-by: Doug Rinckes --- go/encode.go | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/go/encode.go b/go/encode.go index 04dcc166..93135b19 100644 --- a/go/encode.go +++ b/go/encode.go @@ -62,7 +62,9 @@ func Encode(lat, lng float64, codeLen int) string { } // Use a char array so we can build it up from the end digits, without having // to keep reallocating strings. - var code [15]byte + var code [16]byte + // Avoid the need for string concatenation by filling in the Separator manually. + code[sepPos] = Separator // Compute the code. // This approach converts each value to an integer after multiplying it by @@ -74,8 +76,8 @@ func Encode(lat, lng float64, codeLen int) string { var latVal int64 = int64(math.Round((lat+latMax)*finalLatPrecision*1e6) / 1e6) var lngVal int64 = int64(math.Round((lng+lngMax)*finalLngPrecision*1e6) / 1e6) - pos := maxCodeLen - 1 // Compute the grid part of the code if necessary. + pos := maxCodeLen if codeLen > pairCodeLen { for i := 0; i < gridCodeLen; i++ { latDigit := latVal % int64(gridRows) @@ -90,22 +92,31 @@ func Encode(lat, lng float64, codeLen int) string { latVal /= gridLatFullValue lngVal /= gridLngFullValue } - pos = pairCodeLen - 1 + + // Compute the pair after the Separator as a special case rather than + // introduce an if statement to the loop which will only be executed once. + // This also allows us to remove two unnecessary divides at the end of the loop. + latNdx := latVal % int64(encBase) + lngNdx := lngVal % int64(encBase) + code[sepPos+2] = Alphabet[lngNdx] + code[sepPos+1] = Alphabet[latNdx] + // Compute the pair section of the code. - for i := 0; i < pairCodeLen/2; i++ { - latNdx := latVal % int64(encBase) - lngNdx := lngVal % int64(encBase) + pos = sepPos - 1 + for i := 0; i < sepPos/2; i++ { + latVal /= int64(encBase) + lngVal /= int64(encBase) + latNdx = latVal % int64(encBase) + lngNdx = lngVal % int64(encBase) code[pos] = Alphabet[lngNdx] pos -= 1 code[pos] = Alphabet[latNdx] pos -= 1 - latVal /= int64(encBase) - lngVal /= int64(encBase) } // If we don't need to pad the code, return the requested section. if codeLen >= sepPos { - return string(code[:sepPos]) + string(Separator) + string(code[sepPos:codeLen]) + return string(code[:codeLen+1]) } // Pad and return the code. return string(code[:codeLen]) + strings.Repeat(string(Padding), sepPos-codeLen) + string(Separator) From 93f858b9b6ad3a80918d7196aacd6d0c34db5fb9 Mon Sep 17 00:00:00 2001 From: Doug Rinckes Date: Fri, 6 Dec 2024 11:56:45 +0100 Subject: [PATCH 6/6] Update main.yml to ignore unnecessarily generated surefire-report (#641) From #559 (bot authored, CLA not signed): > In our analysis, we observe that this target/surefire-report/ directory is generated but not later used during the CI build. Hence, we propose to disable generating this directory to save runtime. The generation of this directory can be disabled by simply adding -Dsurefire.useFile=false -DdisableXmlReport=true to the mvn command. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f61e5ddf..c4e03e6a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -76,7 +76,7 @@ jobs: distribution: 'temurin' java-version: ${{ matrix.java }} - name: test - run: bazel test --test_output=all ${OLC_PATH}:all && cd ${OLC_PATH} && mvn package + run: bazel test --test_output=all ${OLC_PATH}:all && cd ${OLC_PATH} && mvn package -Dsurefire.useFile=false -DdisableXmlReport=true # Javascript Closure library implementation. Lives in js/closure, tested with bazel. test-js-closure: