001/* 002 * Copyright (C) 2009-2011 Mathias Doenitz 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.parboiled.trees; 018 019import org.parboiled.common.Preconditions; 020 021import java.util.ArrayList; 022import java.util.Collections; 023import java.util.List; 024 025/** 026 * A base implementation of the {@link MutableTreeNode}. 027 * 028 * @param <T> the actual implementation type of this MutableTreeNodeImpl 029 */ 030public class MutableTreeNodeImpl<T extends MutableTreeNode<T>> implements MutableTreeNode<T> { 031 032 private final List<T> children = new ArrayList<T>(); 033 private final List<T> childrenView = Collections.unmodifiableList(children); 034 private T parent; 035 036 public T getParent() { 037 return parent; 038 } 039 040 public List<T> getChildren() { 041 return childrenView; 042 } 043 044 public void addChild(int index, T child) { 045 Preconditions.checkElementIndex(index, children.size() + 1); 046 047 // detach new child from old parent 048 if (child != null) { 049 if (child.getParent() == this) return; 050 if (child.getParent() != null) { 051 TreeUtils.removeChild(child.getParent(), child); 052 } 053 } 054 055 // attach new child 056 children.add(index, child); 057 setParent(child, this); 058 } 059 060 public void setChild(int index, T child) { 061 Preconditions.checkElementIndex(index, children.size()); 062 063 // detach old child 064 T old = children.get(index); 065 if (old == child) return; 066 setParent(old, null); 067 068 // detach new child from old parent 069 if (child != null && child.getParent() != this) { 070 TreeUtils.removeChild(child.getParent(), child); 071 } 072 073 // attach new child 074 children.set(index, child); 075 setParent(child, this); 076 } 077 078 public T removeChild(int index) { 079 Preconditions.checkElementIndex(index, children.size()); 080 T removed = children.remove(index); 081 setParent(removed, null); 082 return removed; 083 } 084 085 @SuppressWarnings("unchecked") 086 private static <T extends MutableTreeNode<T>> void setParent(T node, MutableTreeNodeImpl<T> parent) { 087 if (node != null) { 088 ((MutableTreeNodeImpl) node).parent = parent; 089 } 090 } 091 092}