1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package androidx.constraintlayout.core.parser; 17 18 import org.jspecify.annotations.NonNull; 19 20 import java.util.Arrays; 21 import java.util.Objects; 22 23 /** 24 * Base element to represent a piece of parsed Json. 25 */ 26 public class CLElement implements Cloneable { 27 28 private final char[] mContent; 29 protected long mStart = -1; 30 protected long mEnd = Long.MAX_VALUE; 31 protected CLContainer mContainer; 32 private int mLine; 33 34 protected static int sMaxLine = 80; // Max number of characters before the formatter indents 35 protected static int sBaseIndent = 2; // default indentation value 36 CLElement(char[] content)37 public CLElement(char[] content) { 38 mContent = content; 39 } 40 41 // @TODO: add description notStarted()42 public boolean notStarted() { 43 return mStart == -1; 44 } 45 setLine(int line)46 public void setLine(int line) { 47 this.mLine = line; 48 } 49 50 /** 51 * get the line Number 52 * 53 * @return return the line number this element was on 54 */ getLine()55 public int getLine() { 56 return mLine; 57 } 58 setStart(long start)59 public void setStart(long start) { 60 this.mStart = start; 61 } 62 63 /** 64 * The character index this element was started on 65 */ getStart()66 public long getStart() { 67 return this.mStart; 68 } 69 70 /** 71 * The character index this element was ended on 72 */ getEnd()73 public long getEnd() { 74 return this.mEnd; 75 } 76 77 // @TODO: add description setEnd(long end)78 public void setEnd(long end) { 79 if (this.mEnd != Long.MAX_VALUE) { 80 return; 81 } 82 this.mEnd = end; 83 if (CLParser.sDebug) { 84 System.out.println("closing " + this.hashCode() + " -> " + this); 85 } 86 if (mContainer != null) { 87 mContainer.add(this); 88 } 89 } 90 addIndent(StringBuilder builder, int indent)91 protected void addIndent(StringBuilder builder, int indent) { 92 for (int i = 0; i < indent; i++) { 93 builder.append(' '); 94 } 95 } 96 97 @Override toString()98 public String toString() { 99 if (mStart > mEnd || mEnd == Long.MAX_VALUE) { 100 return this.getClass() + " (INVALID, " + mStart + "-" + mEnd + ")"; 101 } 102 String content = new String(mContent); 103 content = content.substring((int) mStart, (int) mEnd + 1); 104 105 return getStrClass() + " (" + mStart + " : " + mEnd + ") <<" + content + ">>"; 106 } 107 getStrClass()108 protected String getStrClass() { 109 String myClass = this.getClass().toString(); 110 return myClass.substring(myClass.lastIndexOf('.') + 1); 111 } 112 getDebugName()113 protected String getDebugName() { 114 if (CLParser.sDebug) { 115 return getStrClass() + " -> "; 116 } 117 return ""; 118 } 119 120 // @TODO: add description content()121 public String content() { 122 String content = new String(mContent); 123 // Handle empty string 124 if (content.length() < 1) { 125 return ""; 126 } 127 if (mEnd == Long.MAX_VALUE || mEnd < mStart) { 128 return content.substring((int) mStart, (int) mStart + 1); 129 } 130 return content.substring((int) mStart, (int) mEnd + 1); 131 } 132 133 /** 134 * Whether this element has any valid content defined. 135 * <p> 136 * The content is valid when {@link #content()} can be called without causing exceptions. 137 */ hasContent()138 public boolean hasContent() { 139 return mContent != null && mContent.length >= 1; 140 } 141 isDone()142 public boolean isDone() { 143 return mEnd != Long.MAX_VALUE; 144 } 145 setContainer(CLContainer element)146 public void setContainer(CLContainer element) { 147 mContainer = element; 148 } 149 getContainer()150 public CLElement getContainer() { 151 return mContainer; 152 } 153 isStarted()154 public boolean isStarted() { 155 return mStart > -1; 156 } 157 toJSON()158 protected String toJSON() { 159 return ""; 160 } 161 toFormattedJSON(int indent, int forceIndent)162 protected String toFormattedJSON(int indent, int forceIndent) { 163 return ""; 164 } 165 166 // @TODO: add description getInt()167 public int getInt() { 168 if (this instanceof CLNumber) { 169 return ((CLNumber) this).getInt(); 170 } 171 return 0; 172 } 173 174 // @TODO: add description getFloat()175 public float getFloat() { 176 if (this instanceof CLNumber) { 177 return ((CLNumber) this).getFloat(); 178 } 179 return Float.NaN; 180 } 181 182 @Override equals(Object o)183 public boolean equals(Object o) { 184 if (this == o) return true; 185 if (!(o instanceof CLElement)) return false; 186 187 CLElement clElement = (CLElement) o; 188 189 if (mStart != clElement.mStart) return false; 190 if (mEnd != clElement.mEnd) return false; 191 if (mLine != clElement.mLine) return false; 192 if (!Arrays.equals(mContent, clElement.mContent)) return false; 193 return Objects.equals(mContainer, clElement.mContainer); 194 } 195 196 @Override hashCode()197 public int hashCode() { 198 // Auto-generated with Intellij Action "equals() and hashcode()" 199 int result = Arrays.hashCode(mContent); 200 result = 31 * result + (int) (mStart ^ (mStart >>> 32)); 201 result = 31 * result + (int) (mEnd ^ (mEnd >>> 32)); 202 result = 31 * result + (mContainer != null ? mContainer.hashCode() : 0); 203 result = 31 * result + mLine; 204 return result; 205 } 206 207 @Override clone()208 public @NonNull CLElement clone() { 209 try { 210 return (CLElement) super.clone(); 211 } catch (CloneNotSupportedException e) { 212 throw new AssertionError(); 213 } 214 } 215 }