All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jdom.JDOMInterner Maven / Gradle / Ivy

There is a newer version: 2.1.0-Beta1-1.0.25
Show newest version
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jdom;

import com.intellij.openapi.util.Comparing;
import com.intellij.util.containers.Interner;
import it.unimi.dsi.fastutil.Hash;
import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.List;

import static com.intellij.openapi.util.JDOMUtil.getAttributes;

public final class JDOMInterner {
  @ApiStatus.Internal
  public static final JDOMInterner INSTANCE = new JDOMInterner();

  private final Interner myStrings = Interner.createStringInterner();
  private final ObjectOpenCustomHashSet myElements = new ObjectOpenCustomHashSet<>(new Hash.Strategy() {
    @Override
    public int hashCode(Element e) {
      return JDOMInterner.hashCode(e);
    }

    @Override
    public boolean equals(Element o1, Element o2) {
      return JDOMInterner.equals(o1, o2);
    }
  });

  private static int computeAttributesHashCode(Element e) {
    List attributes = getAttributes(e);
    if (attributes instanceof ImmutableSameTypeAttributeList) {
      return attributes.hashCode();
    }
    int result = 1;
    for (Attribute attribute : attributes) {
      result = result * 31 + computeAttributeHashCode(attribute.getName(), attribute.getValue());
    }
    return result;
  }

  private static boolean attributesEqual(Element o1, Element o2) {
    if (o1 instanceof ImmutableElement)  {
      return ((ImmutableElement)o1).attributesEqual(o2);
    }
    if (o2 instanceof ImmutableElement)  {
      return ((ImmutableElement)o2).attributesEqual(o1);
    }
    List a1 = getAttributes(o1);
    List a2 = getAttributes(o2);
    if (a1.size() != a2.size()) return false;
    for (int i=0; i myTexts = new ObjectOpenCustomHashSet<>(new Hash.Strategy() {
    @Override
    public int hashCode(Text object) {
      return computeTextHashCode(object);
    }

    @Override
    public boolean equals(Text o1, Text o2) {
      return o1 == o2 || (o1 != null && o2 != null && Comparing.strEqual(o1.getValue(), o2.getValue()));
    }
  });

  private static int computeTextHashCode(Text object) {
    return object.getValue().hashCode();
  }

  @NotNull
  public synchronized Element internElement(@NotNull final Element element) {
    if (element instanceof ImmutableElement) {
      return element;
    }

    for (Content content : element.getContent()) {
      if (content instanceof Element) {
        return new ImmutableElement(element, this);
      }
    }

    Element interned = myElements.get(element);
    if (interned == null) {
      interned = new ImmutableElement(element, this);
      myElements.add(interned);
    }
    return interned;
  }

  public static boolean isInterned(@NotNull Element element) {
    return element instanceof ImmutableElement;
  }

  @NotNull
  synchronized Text internText(@NotNull Text text) {
    if (text instanceof ImmutableText || text instanceof ImmutableCDATA) return text;
    Text interned = myTexts.get(text);
    if (interned == null) {
      // no need to intern CDATA - there are no duplicates anyway
      interned = text instanceof CDATA ? new ImmutableCDATA(text.getText()) : new ImmutableText(myStrings.intern(text.getText()));
      myTexts.add(interned);
    }
    return interned;
  }

  synchronized String internString(String s) {
    return myStrings.intern(s);
  }

  public static int hashCode(@Nullable Element e) {
    if (e == null) {
      return 0;
    }
    int result = e.getName().hashCode() * 31;
    result += computeAttributesHashCode(e);
    List content = e.getContent();
    result = result * 31 + content.size();
    for (Content child : content) {
      if (child instanceof Text) {
        result = result * 31 + computeTextHashCode((Text)child);
      }
      else if (child instanceof Element) {
        result = result * 31 + hashCode((Element)child);
        break;
      }
    }
    return result;
  }

  public static boolean equals(@Nullable Element o1, @Nullable Element o2) {
    if (o1 == o2) {
      return true;
    }

    if (o1 == null || o2 == null || !Comparing.strEqual(o1.getName(), o2.getName()) || !attributesEqual(o1, o2)) {
      return false;
    }

    List content1 = o1.getContent();
    List content2 = o2.getContent();
    if (content1.size() != content2.size()) return false;
    for (int i = 0; i < content1.size(); i++) {
      Content c1 = content1.get(i);
      Content c2 = content2.get(i);
      if (c1 instanceof Text) {
        if (!(c2 instanceof Text) || !Comparing.strEqual(c1.getValue(), c2.getValue())) {
          return false;
        }
      }
      else if (c1 instanceof Element) {
        if (!(c2 instanceof Element) || !equals((Element)c1, (Element)c2)) {
          return false;
        }
      }
      else {
        throw new RuntimeException(c1.toString());
      }
    }
    return true;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy