package binary // Serialize tags to a array of interleaved key and value strings. // Common tags like building=yes are serialized to a single unicode // char to save a few bytes. Common keys to a single ASCII ctrl char. // Common tags are encoded as a single unicode char from the Unicode // Private Use Area http://en.wikipedia.org/wiki/Private_Use_(Unicode) // between U+E000 and U+F8FF. They take three bytes in UTF-8 encoding. // // For example: building=yes will need 4 bytes instead of 13 bytes. // (building=8 + yes=3 + 2x1 for string length, vs. 3+1) // The most common tag kays with variable values (name, addr:street, // etc.) are converted to a single ASCII control char (0x01-0x1f) import ( "github.com/omniscale/imposm3/element" "unicode/utf8" ) type codepoint rune type tag struct { Key string Value string } var tagsToCodePoint = map[string]map[string]codepoint{} var codePointToTag = map[codepoint]tag{} var commonKeys = map[string]codepoint{} var codePointToCommonKey = map[uint8]string{} var nextKeyCodePoint = codepoint(1) var maxKeyCodePoint = codepoint(31) const minCodePoint = codepoint('\uE000') const maxCodePoint = codepoint('\uF8FF') var nextCodePoint = codepoint('\uE000') func addTagCodePoint(key, value string) { if nextCodePoint > maxCodePoint { panic("all codepoints used!") } valMap, ok := tagsToCodePoint[key] if !ok { tagsToCodePoint[key] = map[string]codepoint{value: nextCodePoint} } else { if _, ok := valMap[value]; ok { panic("duplicate entry for tag codepoints: " + key + " " + value) } valMap[value] = nextCodePoint } codePointToTag[nextCodePoint] = tag{key, value} nextCodePoint += 1 } func addCommonKey(key string) { if nextKeyCodePoint > maxKeyCodePoint { panic("all codepoints used!") } commonKeys[key] = nextKeyCodePoint codePointToCommonKey[uint8(nextKeyCodePoint)] = key nextKeyCodePoint += 1 } func tagsFromArray(arr []string) element.Tags { if len(arr) == 0 { return element.Tags{} } result := make(element.Tags) for i := 0; i < len(arr); i += 1 { if r, size := utf8.DecodeRuneInString(arr[i]); size >= 3 && codepoint(r) >= minCodePoint && codepoint(r) < nextCodePoint { tag, ok := codePointToTag[codepoint(r)] if !ok { panic("missing tag for codepoint") } result[tag.Key] = tag.Value } else if len(arr[i]) > 0 && arr[i][0] < 32 { result[codePointToCommonKey[arr[i][0]]] = arr[i][1:] } else { result[arr[i]] = arr[i+1] i++ } } return result } func tagsAsArray(tags element.Tags) []string { if len(tags) == 0 { return nil } result := make([]string, 0, 2*len(tags)) for key, val := range tags { if valMap, ok := tagsToCodePoint[key]; ok { if codePoint, ok := valMap[val]; ok { result = append(result, string(codePoint)) continue } } if codepoint, ok := commonKeys[key]; ok { result = append(result, string(codepoint)+val) continue } result = append(result, key, val) } return result } func init() { // // DO NOT EDIT, REMOVE, REORDER ANY OF THE FOLLOWING LINES! // // most common keys with variable values // there are only 31 code points for common keys addCommonKey("name") addCommonKey("addr:street") addCommonKey("addr:place") addCommonKey("addr:city") addCommonKey("addr:postcode") addCommonKey("addr:housenumber") // most used tags for ways // addTagCodePoint("building", "yes") addTagCodePoint("highway", "residential") addTagCodePoint("highway", "service") addTagCodePoint("wall", "no") addTagCodePoint("highway", "unclassified") addTagCodePoint("waterway", "stream") addTagCodePoint("highway", "track") addTagCodePoint("natural", "water") addTagCodePoint("oneway", "yes") addTagCodePoint("highway", "footway") addTagCodePoint("highway", "tertiary") addTagCodePoint("access", "private") addTagCodePoint("highway", "path") addTagCodePoint("highway", "secondary") addTagCodePoint("landuse", "forest") addTagCodePoint("building", "house") addTagCodePoint("bridge", "yes") addTagCodePoint("surface", "asphalt") addTagCodePoint("natural", "wood") addTagCodePoint("foot", "yes") addTagCodePoint("landuse", "residential") addTagCodePoint("surface", "paved") addTagCodePoint("highway", "primary") addTagCodePoint("surface", "unpaved") addTagCodePoint("landuse", "grass") addTagCodePoint("building", "residential") addTagCodePoint("service", "parking_aisle") addTagCodePoint("oneway", "no") addTagCodePoint("railway", "rail") addTagCodePoint("bicycle", "yes") addTagCodePoint("service", "driveway") addTagCodePoint("amenity", "parking") addTagCodePoint("area", "yes") addTagCodePoint("barrier", "fence") addTagCodePoint("tracktype", "grade2") addTagCodePoint("natural", "coastline") addTagCodePoint("tracktype", "grade3") addTagCodePoint("intermittent", "yes") addTagCodePoint("landuse", "farmland") addTagCodePoint("building", "hut") addTagCodePoint("boundary", "administrative") addTagCodePoint("lit", "yes") addTagCodePoint("highway", "cycleway") addTagCodePoint("landuse", "meadow") addTagCodePoint("waterway", "river") addTagCodePoint("natural", "wetland") addTagCodePoint("highway", "trunk") addTagCodePoint("surface", "gravel") addTagCodePoint("tracktype", "grade1") addTagCodePoint("barrier", "wall") addTagCodePoint("building", "garage") addTagCodePoint("highway", "living_street") addTagCodePoint("highway", "motorway") addTagCodePoint("tracktype", "grade4") addTagCodePoint("landuse", "farm") addTagCodePoint("leisure", "pitch") addTagCodePoint("surface", "ground") addTagCodePoint("tunnel", "yes") addTagCodePoint("highway", "motorway_link") addTagCodePoint("bicycle", "no") addTagCodePoint("highway", "road") addTagCodePoint("natural", "scrub") addTagCodePoint("highway", "steps") addTagCodePoint("foot", "designated") addTagCodePoint("waterway", "ditch") addTagCodePoint("admin_level", "8") addTagCodePoint("tracktype", "grade5") addTagCodePoint("access", "yes") addTagCodePoint("building", "apartments") addTagCodePoint("leisure", "swimming_pool") addTagCodePoint("junction", "roundabout") addTagCodePoint("highway", "pedestrian") addTagCodePoint("barrier", "hedge") addTagCodePoint("bicycle", "designated") addTagCodePoint("leisure", "park") addTagCodePoint("service", "alley") addTagCodePoint("landuse", "farmyard") addTagCodePoint("building", "industrial") addTagCodePoint("waterway", "riverbank") addTagCodePoint("building", "roof") addTagCodePoint("surface", "dirt") addTagCodePoint("waterway", "drain") addTagCodePoint("surface", "grass") addTagCodePoint("amenity", "school") addTagCodePoint("power", "line") addTagCodePoint("landuse", "industrial") addTagCodePoint("landuse", "reservoir") addTagCodePoint("water", "intermittent") addTagCodePoint("highway", "trunk_link") addTagCodePoint("segregated", "no") addTagCodePoint("horse", "no") addTagCodePoint("wood", "deciduous") addTagCodePoint("highway", "primary_link") addTagCodePoint("foot", "no") addTagCodePoint("lit", "no") addTagCodePoint("surface", "concrete") addTagCodePoint("building", "garages") addTagCodePoint("amenity", "place_of_worship") addTagCodePoint("religion", "christian") addTagCodePoint("waterway", "canal") addTagCodePoint("landuse", "orchard") addTagCodePoint("surface", "paving_stones") addTagCodePoint("leisure", "garden") addTagCodePoint("service", "spur") addTagCodePoint("living_street", "yes") addTagCodePoint("access", "permissive") addTagCodePoint("sport", "soccer") addTagCodePoint("frequency", "0") addTagCodePoint("landuse", "cemetery") addTagCodePoint("wood", "mixed") addTagCodePoint("motorcar", "no") addTagCodePoint("access", "no") addTagCodePoint("man_made", "pier") addTagCodePoint("oneway", "-1") addTagCodePoint("sport", "tennis") addTagCodePoint("noexit", "yes") addTagCodePoint("service", "yard") addTagCodePoint("wood", "coniferous") addTagCodePoint("natural", "cliff") addTagCodePoint("leisure", "playground") addTagCodePoint("cycleway", "lane") addTagCodePoint("surface", "cobblestone") addTagCodePoint("landuse", "vineyard") addTagCodePoint("frequency", "16.7") // // most used tags for nodes // addTagCodePoint("power", "tower") addTagCodePoint("natural", "tree") addTagCodePoint("highway", "bus_stop") addTagCodePoint("power", "pole") addTagCodePoint("place", "locality") addTagCodePoint("highway", "turning_circle") addTagCodePoint("highway", "crossing") addTagCodePoint("place", "village") addTagCodePoint("place", "hamlet") addTagCodePoint("highway", "traffic_signals") addTagCodePoint("barrier", "gate") // addTagCodePoint("admin_level", "8") // addTagCodePoint("amenity", "place_of_worship") // addTagCodePoint("amenity", "school") // addTagCodePoint("religion", "christian") addTagCodePoint("amenity", "bench") addTagCodePoint("man_made", "survey_point") addTagCodePoint("amenity", "restaurant") // addTagCodePoint("amenity", "parking") addTagCodePoint("natural", "peak") addTagCodePoint("railway", "level_crossing") addTagCodePoint("type", "broad_leaved") // addTagCodePoint("building", "yes") // addTagCodePoint("foot", "yes") // addTagCodePoint("bicycle", "yes") addTagCodePoint("highway", "street_lamp") addTagCodePoint("tourism", "information") addTagCodePoint("wheelchair", "yes") addTagCodePoint("building", "entrance") addTagCodePoint("public_transport", "stop_position") addTagCodePoint("amenity", "fuel") // addTagCodePoint("noexit", "yes") addTagCodePoint("barrier", "bollard") addTagCodePoint("amenity", "post_box") addTagCodePoint("natural", "rock") // addTagCodePoint("landuse", "forest") addTagCodePoint("shelter", "yes") addTagCodePoint("emergency", "fire_hydrant") addTagCodePoint("public_transport", "platform") addTagCodePoint("amenity", "grave_yard") addTagCodePoint("shop", "convenience") addTagCodePoint("power", "generator") addTagCodePoint("shop", "supermarket") addTagCodePoint("amenity", "bank") addTagCodePoint("amenity", "fast_food") addTagCodePoint("amenity", "cafe") // // most used tags for rels // addTagCodePoint("type", "multipolygon") addTagCodePoint("type", "route") // addTagCodePoint("boundary", "administrative") addTagCodePoint("type", "restriction") addTagCodePoint("type", "boundary") addTagCodePoint("type", "site") // addTagCodePoint("admin_level", "8") addTagCodePoint("type", "associatedStreet") // addTagCodePoint("natural", "water") }