Unicode.java

  1. /*
  2.  * Copyright (c) 2016, Stein Eldar Johnsen
  3.  *
  4.  * Licensed to the Apache Software Foundation (ASF) under one
  5.  * or more contributor license agreements. See the NOTICE file
  6.  * distributed with this work for additional information
  7.  * regarding copyright ownership. The ASF licenses this file
  8.  * to you under the Apache License, Version 2.0 (the
  9.  * "License"); you may not use this file except in compliance
  10.  * with the License. You may obtain a copy of the License at
  11.  *
  12.  *   http://www.apache.org/licenses/LICENSE-2.0
  13.  *
  14.  * Unless required by applicable law or agreed to in writing,
  15.  * software distributed under the License is distributed on an
  16.  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  17.  * KIND, either express or implied. See the License for the
  18.  * specific language governing permissions and limitations
  19.  * under the License.
  20.  */
  21. package net.morimekta.strings.chr;

  22. import java.util.Objects;

  23. import static java.lang.Character.isBmpCodePoint;
  24. import static net.morimekta.strings.ConsoleUtil.isConsolePrintable;

  25. /**
  26.  * Representation of a unicode character. It represents the full 31-but unicode
  27.  * code point, and will expand to the 2 surrogate paired string if necessary.
  28.  */
  29. public class Unicode
  30.         implements Char {
  31.     /**
  32.      * No-break space.
  33.      */
  34.     public static final Unicode NBSP         = unicode(0x00A0);
  35.     /**
  36.      * sets base direction to LTR and isolates the embedded content from the surrounding text
  37.      */
  38.     public static final Unicode LTR_ISOLATE  = unicode(0x2066);
  39.     /**
  40.      * ditto, but for RTL
  41.      */
  42.     public static final Unicode RTL_ISOLATE  = unicode(0x2067);
  43.     /**
  44.      * isolates the content and sets the direction according to the first strongly typed directional character
  45.      */
  46.     public static final Unicode FS_ISOLATE   = unicode(0x2068);
  47.     /**
  48.      * sets base direction to LTR but allows embedded text to interact with surrounding content, so risk of spillover effects
  49.      */
  50.     public static final Unicode LTR_EMBED    = unicode(0x202A);
  51.     /**
  52.      * ditto, but for RTL
  53.      */
  54.     public static final Unicode RTL_EMBED    = unicode(0x202B);
  55.     /**
  56.      * overrides the bidirectional algorithm to display characters in memory order, progressing from left to right
  57.      */
  58.     public static final Unicode LTR_OVERRIDE = unicode(0x202D);
  59.     /**
  60.      * as previous, but display progresses from right to left
  61.      */
  62.     public static final Unicode RTL_OVERRIDE = unicode(0x202E);

  63.     /**
  64.      * Create a unicode instance.
  65.      *
  66.      * @param cp Code point of unicode character, can be BMP or extended.
  67.      * @return The unicode char.
  68.      */
  69.     public static Unicode unicode(int cp) {
  70.         return new Unicode(cp);
  71.     }

  72.     /**
  73.      * Create a unicode instance.
  74.      *
  75.      * @param ch The unicode character (BMP).
  76.      * @return The  unicode char.
  77.      */
  78.     public static Unicode unicode(char ch) {
  79.         return new Unicode(ch);
  80.     }

  81.     private final int cp;

  82.     /**
  83.      * Create a unicode instance.
  84.      *
  85.      * @param cp Character code point.
  86.      */
  87.     public Unicode(int cp) {
  88.         this.cp = cp;
  89.     }

  90.     /**
  91.      * Create a unicode instance.
  92.      *
  93.      * @param ch Unicode character.
  94.      */
  95.     public Unicode(char ch) {
  96.         this.cp = ch;
  97.     }

  98.     @Override
  99.     public int codepoint() {
  100.         return cp;
  101.     }

  102.     @Override
  103.     public String asString() {
  104.         StringBuilder builder = new StringBuilder();
  105.         switch (cp) {
  106.             case NUL:
  107.                 return "<NUL>";
  108.             case ABR:
  109.                 return "<ABR>";
  110.             case EOF:
  111.                 return "<EOF>";
  112.             case ENQ:
  113.                 return "<ENQ>";
  114.             case ACK:
  115.                 return "<ACK>";
  116.             case NAK:
  117.                 return "<NAK>";
  118.             case BEL:
  119.                 return "<BEL>"; // Not using '\a', as not universal.
  120.             case BS:
  121.                 return "<BS>";  // Not using '\b'. It conflicts with C definition of BEL.
  122.             case VT:
  123.                 return "<VT>";
  124.             case SS:
  125.                 return "<SS>";
  126.             case SI:
  127.                 return "<SI>";
  128.             case ESC:
  129.                 return "<ESC>";
  130.             case CAN:
  131.                 return "<CAN>";
  132.             case XON:
  133.                 return "<XON>";
  134.             case XOFF:
  135.                 return "<XOFF>";
  136.             case FS:
  137.                 return "<FS>";
  138.             case GS:
  139.                 return "<GS>";
  140.             case RS:
  141.                 return "<RS>";
  142.             case US:
  143.                 return "<US>";
  144.             case DEL:
  145.                 return "<DEL>";  // backspace??
  146.             case 0x00A0:
  147.                 return "<nbsp>";
  148.             case 0x2066:
  149.                 return "<ltr-isolate>";
  150.             case 0x2067:
  151.                 return "<rtl-isolate>";
  152.             case 0x2068:
  153.                 return "<fs-isolate>";
  154.             case 0x202A:
  155.                 return "<ltr-embedded>";
  156.             case 0x202B:
  157.                 return "<rtl-embedded>";
  158.             case 0x202D:
  159.                 return "<ltr-override>";
  160.             case 0x202E:
  161.                 return "<rtl-override>";
  162.             case TAB:
  163.                 builder.append('\\').append('t');
  164.                 break;
  165.             case LF:
  166.                 builder.append('\\').append('n');
  167.                 break;
  168.             case FF:
  169.                 builder.append('\\').append('f');
  170.                 break;
  171.             case CR:
  172.                 builder.append('\\').append('r');
  173.                 break;
  174.             case '\"':
  175.             case '\'':
  176.             case '\\':
  177.                 builder.append('\\').append((char) cp);
  178.                 break;
  179.             default:
  180.                 if (cp < 0x20) {
  181.                     // Use escaped octal value encoding.
  182.                     builder.append(String.format("\\%03o", cp));
  183.                 } else if (isConsolePrintable(cp)) {
  184.                     if (isBmpCodePoint(cp)) {
  185.                         builder.append((char) cp);
  186.                     } else {
  187.                         builder.append(Character.highSurrogate(cp));
  188.                         builder.append(Character.lowSurrogate(cp));
  189.                     }
  190.                 } else {
  191.                     if (isBmpCodePoint(cp)) {
  192.                         builder.append(String.format("\\u%04x", cp));
  193.                     } else {
  194.                         builder.append(String.format("\\u%04x", (int) Character.highSurrogate(cp)));
  195.                         builder.append(String.format("\\u%04x", (int) Character.lowSurrogate(cp)));
  196.                     }
  197.                 }
  198.                 break;
  199.         }
  200.         return builder.toString();
  201.     }

  202.     @Override
  203.     public int printableWidth() {
  204.         if (cp < 0x0300) {
  205.             // Control characters, accents, etc.
  206.             if (cp < 0x20 ||
  207.                 (0x7F <= cp && cp < 0xA0)) {
  208.                 return 0;
  209.             }
  210.         } else if (cp < 0x0600) {
  211.             if ((cp < 0x0370) || // 0-width punctuation
  212.                 (0x0483 <= cp && cp <= 0x0489) || // 0-width symbols
  213.                 (0x0591 <= cp && cp <= 0x05c7 &&  // 0-width sanskrit accents
  214.                  cp != 0x05be && cp != 0x05c0 && cp != 0x05c3 && cp != 0x05c6)) {
  215.                 return 0;
  216.             }
  217.         } else if (cp < 0x0800) {
  218.             if ((cp <= 0x0605) || // 0-width hebrew accents
  219.                 (0x0610 <= cp && cp <= 0x061a) || cp == 0x061c || // 0-width arabic accents
  220.                 cp == 0x064b ||
  221.                 (0x064c <= cp && cp <= 0x065f) || cp == 0x0670 ||  // 0-width arabic accents (2)
  222.                 (0x06d6 <= cp && cp <= 0x06ed && // 0-width symbols (2)
  223.                  cp != 0x06de && cp != 0x06e5 && cp != 0x06e6 && cp != 0x06e9) ||
  224.                 cp == 0x070f || cp == 0x0711 ||
  225.                 (0x0730 <= cp && cp <= 0x074a) ||
  226.                 (0x07a6 <= cp && cp <= 0x07b0) ||
  227.                 (0x07eb <= cp && cp <= 0x07f3) ||
  228.                 cp == 0x07fd) {
  229.                 return 0;
  230.             }
  231.         } else if (cp < 0x1000) {
  232.             if ((0x0816 <= cp && cp <= 0x082d &&
  233.                  cp != 0x081a && cp != 0x0824 && cp != 0x0828) ||
  234.                 cp == 0x0859 || cp == 0x085a || cp == 0x085b ||
  235.                 cp == 0x0890 || cp == 0x0891 ||
  236.                 (0x0898 <= cp && cp <= 0x089f) ||
  237.                 (0x08ca <= cp && cp <= 0x0902) ||
  238.                 cp == 0x093a || cp == 0x093c ||
  239.                 (0x0941 <= cp && cp <= 0x0948) || cp == 0x094d ||
  240.                 (0x0951 <= cp && cp <= 0x0957) ||
  241.                 cp == 0x0962 || cp == 0x0963 ||
  242.                 cp == 0x0981 || cp == 0x09bc ||
  243.                 (0x09c1 <= cp && cp <= 0x09c4) ||
  244.                 cp == 0x09cd ||
  245.                 cp == 0x09e2 || cp == 0x09e3 ||
  246.                 cp == 0x09fe ||
  247.                 cp == 0x0a01 || cp == 0x0a02 ||
  248.                 cp == 0x0a3c ||
  249.                 cp == 0x0a41 || cp == 0x0a42 ||
  250.                 cp == 0x0a47 || cp == 0x0a48 ||
  251.                 cp == 0x0a4b || cp == 0x0a4c || cp == 0x0a4d ||
  252.                 cp == 0x0a51 ||
  253.                 cp == 0x0a70 || cp == 0x0a71 ||
  254.                 cp == 0x0a75 ||
  255.                 cp == 0x0a81 || cp == 0x0a82 ||
  256.                 cp == 0x0abc ||
  257.                 (0x0ac1 <= cp && cp <= 0x0ac8 && cp != 0x0ac6) ||
  258.                 cp == 0x0acd ||
  259.                 cp == 0x0ae2 || cp == 0x0ae3 ||
  260.                 (0x0afa <= cp && cp <= 0x0aff) ||
  261.                 cp == 0x0b01 ||
  262.                 cp == 0x0b3c ||
  263.                 cp == 0x0b3f ||
  264.                 cp == 0x0b41 || cp == 0x0b42 || cp == 0x0b43 || cp == 0x0b44 ||
  265.                 cp == 0x0b4d ||
  266.                 cp == 0x0b55 || cp == 0x0b56 ||
  267.                 cp == 0x0b62 || cp == 0x0b63 ||
  268.                 cp == 0x0b82 ||
  269.                 cp == 0x0bc0 ||
  270.                 cp == 0x0bcd ||
  271.                 cp == 0x0c00 ||
  272.                 cp == 0x0c04 ||
  273.                 cp == 0x0c3c ||
  274.                 cp == 0x0c3e || cp == 0x0c3f ||
  275.                 cp == 0x0c40 ||
  276.                 cp == 0x0c46 || cp == 0x0c47 || cp == 0x0c48 ||
  277.                 cp == 0x0c4a || cp == 0x0c4b || cp == 0x0c4c || cp == 0x0c4d ||
  278.                 cp == 0x0c55 || cp == 0x0c56 ||
  279.                 cp == 0x0c62 || cp == 0x0c63 ||
  280.                 cp == 0x0c81 ||
  281.                 cp == 0x0cbc || cp == 0x0cbf ||
  282.                 cp == 0x0cc6 ||
  283.                 cp == 0x0ccc || cp == 0x0ccd ||
  284.                 cp == 0x0ce2 || cp == 0x0ce3 ||
  285.                 cp == 0x0d00 ||
  286.                 cp == 0x0d01 ||
  287.                 cp == 0x0d3b ||
  288.                 cp == 0x0d3c ||
  289.                 cp == 0x0d41 || cp == 0x0d42 || cp == 0x0d43 || cp == 0x0d44 ||
  290.                 cp == 0x0d4d ||
  291.                 cp == 0x0d62 || cp == 0x0d63 ||
  292.                 cp == 0x0d81 ||
  293.                 cp == 0x0dca ||
  294.                 cp == 0x0dd2 || cp == 0x0dd3 ||
  295.                 cp == 0x0dd4 || cp == 0x0dd6 ||
  296.                 cp == 0x0e31 ||
  297.                 (0x0e34 <= cp && cp <= 0x0e3a) ||
  298.                 (0x0e47 <= cp && cp <= 0x0e4e) ||
  299.                 cp == 0x0eb1 ||
  300.                 (0x0eb4 <= cp && cp <= 0x0ebc) ||
  301.                 (0x0ec8 <= cp && cp <= 0x0ece) ||
  302.                 cp == 0x0f18 || cp == 0x0f19 ||
  303.                 cp == 0x0f35 ||
  304.                 cp == 0x0f37 ||
  305.                 cp == 0x0f39 ||
  306.                 (0x0f71 <= cp && cp <= 0x0f87 && cp != 0x0f7f && cp != 0x0f85) ||
  307.                 (0x0f8d <= cp && cp <= 0x0fbc && cp != 0x0f98) ||
  308.                 cp == 0x0fc6) {
  309.                 return 0;
  310.             }
  311.         } else if (cp < 0x2000) {
  312.             if (cp < 0x1360) {
  313.                 if (0x1100 <= cp && cp < 0x1160) {
  314.                     return 2;
  315.                 } else if ((0x102d <= cp && cp <= 0x1037 && cp != 0x1031) ||
  316.                            cp == 0x1039 ||
  317.                            cp == 0x103a ||
  318.                            cp == 0x103d || cp == 0x103e ||
  319.                            cp == 0x1058 || cp == 0x1059 ||
  320.                            cp == 0x105e || cp == 0x105f ||
  321.                            cp == 0x1060 ||
  322.                            cp == 0x1071 || cp == 0x1072 || cp == 0x1073 || cp == 0x1074 ||
  323.                            cp == 0x1082 ||
  324.                            cp == 0x1085 || cp == 0x1086 ||
  325.                            cp == 0x108d ||
  326.                            cp == 0x109d ||
  327.                            (0x1160 <= cp && cp <= 0x11ff) ||
  328.                            cp == 0x135d || cp == 0x135e || cp == 0x135f) {
  329.                     return 0;
  330.                 }
  331.             } else if (0x1700 < cp) {
  332.                 if ((0x1712 <= cp && cp <= 0x1714) ||
  333.                     cp == 0x1732 || cp == 0x1733 ||
  334.                     cp == 0x1752 || cp == 0x1753 ||
  335.                     cp == 0x1772 || cp == 0x1773 ||
  336.                     (0x17b4 <= cp && cp <= 0x17bd && cp != 0x17b6) ||
  337.                     cp == 0x17c6 ||
  338.                     (0x17c9 <= cp && cp <= 0x17d3) ||
  339.                     cp == 0x17dd ||
  340.                     (0x180b <= cp && cp <= 0x180f) ||
  341.                     cp == 0x1885 || cp == 0x1886 ||
  342.                     cp == 0x18a9 ||
  343.                     (0x1920 <= cp && cp <= 0x1922) ||
  344.                     cp == 0x1927 || cp == 0x1928 ||
  345.                     cp == 0x1932 ||
  346.                     cp == 0x1939 || cp == 0x193a || cp == 0x193b ||

  347.                     cp == 0x1a17 || cp == 0x1a18 ||
  348.                     cp == 0x1a1b ||
  349.                     cp == 0x1a56 ||
  350.                     (0x1a58 <= cp && cp <= 0x1a5e) ||
  351.                     cp == 0x1a60 ||
  352.                     cp == 0x1a62 ||
  353.                     (0x1a65 <= cp && cp <= 0x1a6c) ||
  354.                     (0x1a73 <= cp && cp <= 0x1a7c) ||
  355.                     cp == 0x1a7f ||
  356.                     (0x1ab0 <= cp && cp <= 0x1ace) ||
  357.                     (0x1b00 <= cp && cp <= 0x1b03) ||
  358.                     cp == 0x1b34 ||
  359.                     (0x1b36 <= cp && cp <= 0x1b3a) ||
  360.                     cp == 0x1b3c ||
  361.                     cp == 0x1b42 ||
  362.                     (0x1b6b <= cp && cp <= 0x1b73) ||
  363.                     cp == 0x1b80 || cp == 0x1b81 ||
  364.                     (0x1ba2 <= cp && cp <= 0x1ba5) ||
  365.                     cp == 0x1ba8 || cp == 0x1ba9 ||
  366.                     cp == 0x1bab || cp == 0x1bac || cp == 0x1bad ||
  367.                     cp == 0x1be6 ||
  368.                     cp == 0x1be8 || cp == 0x1be9 ||
  369.                     cp == 0x1bed ||
  370.                     cp == 0x1bef ||
  371.                     cp == 0x1bf0 || cp == 0x1bf1 ||
  372.                     (0x1c2c <= cp && cp <= 0x1c33) ||
  373.                     cp == 0x1c36 || cp == 0x1c37 ||
  374.                     (0x1cd0 <= cp && cp <= 0x1ce8 &&
  375.                      cp != 0x1cd3 && cp != 0x1ce1) ||
  376.                     cp == 0x1ced ||
  377.                     cp == 0x1cf4 ||
  378.                     cp == 0x1cf8 || cp == 0x1cf9 ||
  379.                     (0x1dc0 <= cp && cp <= 0x1dfb) ||
  380.                     (0x1dfc <= cp && cp <= 0x1dff)) {
  381.                     return 0;
  382.                 }
  383.             }
  384.         } else if (cp < 0x3000) {
  385.             if ((0x200b <= cp && cp <= 0x200f) ||
  386.                 (0x202a <= cp && cp <= 0x202e) ||
  387.                 (0x2060 <= cp && cp <= 0x206f && cp != 0x2065) ||
  388.                 (0x20d0 <= cp && cp <= 0x20ef) ||
  389.                 cp == 0x20f0 ||
  390.                 cp == 0x2d7f ||
  391.                 cp == 0x2cef || cp == 0x2cf0 || cp == 0x2cf1 ||
  392.                 (0x2de0 <= cp && cp <= 0x2dff)) {
  393.                 return 0;
  394.             } else if ((0x231a <= cp && cp < 0x231c) ||
  395.                        (0x2329 <= cp && cp < 0x232b) ||
  396.                        (0x23e9 <= cp && cp < 0x23ed) ||
  397.                        cp == 0x23f0 ||
  398.                        cp == 0x23f3 ||
  399.                        (0x25fd <= cp && cp < 0x25ff) ||
  400.                        (0x2614 <= cp && cp < 0x2616) ||
  401.                        (0x2648 <= cp && cp <= 0x2653) ||
  402.                        cp == 0x267f ||
  403.                        cp == 0x2693 ||
  404.                        cp == 0x26a1 ||
  405.                        cp == 0x26aa || cp == 0x26ab ||
  406.                        (0x26bd <= cp && cp <= 0x26be) ||
  407.                        cp == 0x26c4 || cp == 0x26c5 ||
  408.                        cp == 0x26ce ||
  409.                        cp == 0x26d4 ||
  410.                        cp == 0x26ea ||
  411.                        cp == 0x26f2 || cp == 0x26f3 ||
  412.                        cp == 0x26f5 || cp == 0x26fa || cp == 0x26fd ||
  413.                        cp == 0x2705 || cp == 0x270a || cp == 0x270b ||
  414.                        cp == 0x2728 ||
  415.                        cp == 0x274c ||
  416.                        cp == 0x274e ||
  417.                        (0x2753 <= cp && cp <= 0x2755) || cp == 0x2757 ||
  418.                        (0x2795 <= cp && cp <= 0x2797) ||
  419.                        cp == 0x27b0 || cp == 0x27bf ||
  420.                        cp == 0x2b1b || cp == 0x2b1c ||
  421.                        cp == 0x2b50 || cp == 0x2b55 ||
  422.                        (0x2e80 <= cp && cp < 0x2fd6) ||
  423.                        (0x2ff0 <= cp && cp < 0x2ffc)) {
  424.                 if (!(cp == 0x2e9a ||
  425.                       (0x2ef4 <= cp && cp <= 0x2eff))) {
  426.                     return 2;
  427.                 }
  428.             }
  429.         } else if (cp <= 0x10000) {
  430.             // Control characters, accents, etc.
  431.             if (cp < 0x3030) {
  432.                 if (cp == 0x302a ||
  433.                     cp == 0x302b ||
  434.                     cp == 0x302c ||
  435.                     cp == 0x302d) {
  436.                     return 0;
  437.                 }
  438.             } else if (0xa660 < cp) {
  439.                 if ((0xa66f <= cp && cp <= 0xa67d &&
  440.                      cp != 0xa673) ||
  441.                     cp == 0xa6f0 || cp == 0xa6f1 ||
  442.                     cp == 0xa69e || cp == 0xa69f ||
  443.                     cp == 0xa802 ||
  444.                     cp == 0xa806 ||
  445.                     cp == 0xa80b ||
  446.                     cp == 0xa825 || cp == 0xa826 ||
  447.                     cp == 0xa8c4 || cp == 0xa8c5 ||
  448.                     (0xa8e0 <= cp && cp <= 0xa8f1) ||
  449.                     cp == 0xa8ff ||
  450.                     (0xa926 <= cp && cp <= 0xa92d) ||
  451.                     (0xa947 <= cp && cp <= 0xa951) ||
  452.                     (0xa980 <= cp && cp <= 0xa982) ||
  453.                     cp == 0xa9b3 ||
  454.                     (0xa9b6 <= cp && cp <= 0xa9b9) ||
  455.                     cp == 0xa9bc || cp == 0xa9bd ||
  456.                     cp == 0xa9e5 ||
  457.                     (0xaa29 <= cp && cp <= 0xaa2e) ||
  458.                     cp == 0xaa31 || cp == 0xaa32 ||
  459.                     cp == 0xaa35 || cp == 0xaa36 ||
  460.                     cp == 0xaa43 ||
  461.                     cp == 0xaa4c ||
  462.                     cp == 0xaa7c ||
  463.                     cp == 0xaab0 ||
  464.                     cp == 0xaab2 || cp == 0xaab3 || cp == 0xaab4 ||
  465.                     cp == 0xaab7 || cp == 0xaab8 ||
  466.                     cp == 0xaaec || cp == 0xaaed || cp == 0xaabe || cp == 0xaabf ||
  467.                     cp == 0xaac1 ||
  468.                     cp == 0xaaf6 ||
  469.                     cp == 0xabe5 ||
  470.                     cp == 0xabe8 ||
  471.                     cp == 0xabed ||
  472.                     (0xd7b0 <= cp && cp <= 0xd7ff) ||
  473.                     // -- 0xd86f ... ud8a2 prints as if it was width 0, but setting
  474.                     // it here has apparently no effect.
  475.                     // (0xd86f <= cp && cp <= 0xd8a2) ||
  476.                     (0xfe00 <= cp && cp <= 0xfe0f) ||
  477.                     (0xfe20 <= cp && cp <= 0xfe2f) ||
  478.                     cp == 0xfeff ||
  479.                     (0xfff9 <= cp && cp <= 0xfffb)) {
  480.                     return 0;
  481.                 }
  482.             }
  483.             // CJK compatibility (square symbols), Extension A
  484.             if ((cp < 0x4dc0)) {
  485.                 if (cp == 0x3097 ||
  486.                     cp == 0x3099 ||
  487.                     cp == 0x309a) {
  488.                     return 0;
  489.                 }
  490.                 if (!(
  491.                         cp == 0x3040 ||
  492.                         (0x3097 <= cp && cp <= 0x309a) ||
  493.                         (0x3100 <= cp && cp <= 0x3104) ||
  494.                         cp == 0x303f ||
  495.                         cp == 0x3130 ||
  496.                         cp == 0x318f ||
  497.                         (0x31e4 <= cp && cp <= 0x31ef) ||
  498.                         cp == 0x321f ||
  499.                         (0x3248 <= cp && cp <= 0x324f))) {
  500.                     return 2;
  501.                 }
  502.             } else if (
  503.                     (0x4e00 <= cp && cp < 0xa4c7) ||  // CJK Main group of ideographs ↓ ↓
  504.                     (0xa960 <= cp && cp < 0xa97d) ||
  505.                     (0xac00 <= cp && cp < 0xd7a4) ||
  506.                     (0xf900 <= cp && cp < 0xfb00) ||
  507.                     (0xfe10 <= cp && cp < 0xfe1a) ||
  508.                     (0xfe30 <= cp && cp < 0xfe6c) ||
  509.                     (0xff01 <= cp && cp < 0xff61) ||
  510.                     (0xffe0 <= cp && cp < 0xffe7)) {
  511.                 // Some excluded chars and ranges.
  512.                 if (!(
  513.                         (0xa48d <= cp && cp <= 0xa48f) ||
  514.                         cp == 0xfe53 ||
  515.                         cp == 0xfe67)) {
  516.                     // CJK or other double-width character.
  517.                     return 2;
  518.                 }
  519.             }
  520.         } else {
  521.             // Character.isIdeographic(cp) does not mean the same thing as 'double width'.
  522.             if ((0x00020000 <= cp && cp < 0x0002A6C0) ||  // CJK Extension B
  523.                 (0x0002A700 <= cp && cp < 0x0002CEB0)) {  // CJK Extension C, D, E
  524.                 return 2;
  525.             }
  526.         }

  527.         return 1;
  528.     }

  529.     @Override
  530.     public int length() {
  531.         if (!isBmpCodePoint(cp)) {
  532.             return 2;
  533.         }
  534.         return 1;
  535.     }

  536.     @Override
  537.     public boolean equals(Object o) {
  538.         if (o == this) {
  539.             return true;
  540.         }
  541.         if (o == null || !(getClass().equals(o.getClass()))) {
  542.             return false;
  543.         }

  544.         return cp == ((Unicode) o).cp;
  545.     }

  546.     @Override
  547.     public String toString() {
  548.         if (!isBmpCodePoint(cp)) {
  549.             return new String(new char[]{
  550.                     Character.highSurrogate(cp),
  551.                     Character.lowSurrogate(cp)
  552.             });
  553.         }
  554.         return String.valueOf((char) cp);
  555.     }

  556.     @Override
  557.     public int hashCode() {
  558.         return Objects.hash(Unicode.class, cp);
  559.     }

  560.     @Override
  561.     public int compareTo(Char o) {
  562.         return Integer.compare(cp, o.codepoint());
  563.     }
  564. }