From b777f5a9e867c0155b483d43bf6a99ca2931512a Mon Sep 17 00:00:00 2001 From: Yegor Kozlov Date: Thu, 16 Jan 2014 04:56:26 +0000 Subject: [PATCH 01/11] set version.id to 3.11-beta1 git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1558698 13f79535-47bb-0310-9956-ffa450edef68 --- build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.xml b/build.xml index f22d0c2a1..b4ed5f251 100644 --- a/build.xml +++ b/build.xml @@ -51,7 +51,7 @@ under the License. The Apache POI project Ant build. - + From 439ad2907178aea3ab2547e484327f52eda1ce4d Mon Sep 17 00:00:00 2001 From: Andreas Beeker Date: Sat, 18 Jan 2014 00:38:04 +0000 Subject: [PATCH 02/11] Added license headers git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1559297 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/ss/formula/functions/Bin2Dec.java | 21 ++++++++++++- .../poi/ss/formula/functions/Dec2Bin.java | 22 +++++++++++++- .../charts/TestXSSFLineChartData.java | 30 +++++++++++++++++-- .../org/apache/poi/xwpf/TestXWPFBugs.java | 16 ++++++++++ .../org/apache/poi/hmef/TestBugs.java | 16 ++++++++++ .../poi/hssf/dev/BaseXLSIteratingTest.java | 16 ++++++++++ .../poi/hssf/dev/TestBiffDrawingToXml.java | 16 ++++++++++ .../apache/poi/hssf/dev/TestBiffViewer.java | 16 ++++++++++ .../apache/poi/hssf/dev/TestEFBiffViewer.java | 16 ++++++++++ .../poi/hssf/dev/TestFormulaViewer.java | 16 ++++++++++ .../org/apache/poi/hssf/dev/TestReSave.java | 16 ++++++++++ .../apache/poi/hssf/dev/TestRecordLister.java | 16 ++++++++++ .../TestDeltaFunctionsFromSpreadsheet.java | 16 ++++++++++ 13 files changed, 229 insertions(+), 4 deletions(-) diff --git a/src/java/org/apache/poi/ss/formula/functions/Bin2Dec.java b/src/java/org/apache/poi/ss/formula/functions/Bin2Dec.java index c84229d70..added40cc 100644 --- a/src/java/org/apache/poi/ss/formula/functions/Bin2Dec.java +++ b/src/java/org/apache/poi/ss/formula/functions/Bin2Dec.java @@ -1,7 +1,26 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ package org.apache.poi.ss.formula.functions; import org.apache.poi.ss.formula.OperationEvaluationContext; -import org.apache.poi.ss.formula.eval.*; +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.OperandResolver; +import org.apache.poi.ss.formula.eval.ValueEval; /** * Implementation for Excel Bin2Dec() function.

diff --git a/src/java/org/apache/poi/ss/formula/functions/Dec2Bin.java b/src/java/org/apache/poi/ss/formula/functions/Dec2Bin.java index a275c103a..814b3eb2c 100644 --- a/src/java/org/apache/poi/ss/formula/functions/Dec2Bin.java +++ b/src/java/org/apache/poi/ss/formula/functions/Dec2Bin.java @@ -1,7 +1,27 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ package org.apache.poi.ss.formula.functions; import org.apache.poi.ss.formula.OperationEvaluationContext; -import org.apache.poi.ss.formula.eval.*; +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.EvaluationException; +import org.apache.poi.ss.formula.eval.OperandResolver; +import org.apache.poi.ss.formula.eval.StringEval; +import org.apache.poi.ss.formula.eval.ValueEval; /** * Implementation for Excel Bin2Dec() function.

diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/charts/TestXSSFLineChartData.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/charts/TestXSSFLineChartData.java index 6e45ec001..3b7bac759 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/charts/TestXSSFLineChartData.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/charts/TestXSSFLineChartData.java @@ -1,8 +1,34 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ package org.apache.poi.xssf.usermodel.charts; import junit.framework.TestCase; -import org.apache.poi.ss.usermodel.*; -import org.apache.poi.ss.usermodel.charts.*; + +import org.apache.poi.ss.usermodel.Chart; +import org.apache.poi.ss.usermodel.ClientAnchor; +import org.apache.poi.ss.usermodel.Drawing; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.charts.AxisPosition; +import org.apache.poi.ss.usermodel.charts.ChartAxis; +import org.apache.poi.ss.usermodel.charts.ChartDataSource; +import org.apache.poi.ss.usermodel.charts.DataSources; +import org.apache.poi.ss.usermodel.charts.LineChartData; +import org.apache.poi.ss.usermodel.charts.LineChartSerie; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.SheetBuilder; import org.apache.poi.xssf.usermodel.XSSFWorkbook; diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/TestXWPFBugs.java b/src/ooxml/testcases/org/apache/poi/xwpf/TestXWPFBugs.java index f0ddad5ba..f261ae0f6 100644 --- a/src/ooxml/testcases/org/apache/poi/xwpf/TestXWPFBugs.java +++ b/src/ooxml/testcases/org/apache/poi/xwpf/TestXWPFBugs.java @@ -1,3 +1,19 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ package org.apache.poi.xwpf; import static org.junit.Assert.assertEquals; diff --git a/src/scratchpad/testcases/org/apache/poi/hmef/TestBugs.java b/src/scratchpad/testcases/org/apache/poi/hmef/TestBugs.java index 79529a736..6775c9147 100644 --- a/src/scratchpad/testcases/org/apache/poi/hmef/TestBugs.java +++ b/src/scratchpad/testcases/org/apache/poi/hmef/TestBugs.java @@ -1,3 +1,19 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ package org.apache.poi.hmef; import junit.framework.TestCase; diff --git a/src/testcases/org/apache/poi/hssf/dev/BaseXLSIteratingTest.java b/src/testcases/org/apache/poi/hssf/dev/BaseXLSIteratingTest.java index 9433f1345..eb6b5a9d3 100644 --- a/src/testcases/org/apache/poi/hssf/dev/BaseXLSIteratingTest.java +++ b/src/testcases/org/apache/poi/hssf/dev/BaseXLSIteratingTest.java @@ -1,3 +1,19 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ package org.apache.poi.hssf.dev; import static org.junit.Assert.assertNotNull; diff --git a/src/testcases/org/apache/poi/hssf/dev/TestBiffDrawingToXml.java b/src/testcases/org/apache/poi/hssf/dev/TestBiffDrawingToXml.java index 90c7ec218..09a311e86 100644 --- a/src/testcases/org/apache/poi/hssf/dev/TestBiffDrawingToXml.java +++ b/src/testcases/org/apache/poi/hssf/dev/TestBiffDrawingToXml.java @@ -1,3 +1,19 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ package org.apache.poi.hssf.dev; import java.io.File; diff --git a/src/testcases/org/apache/poi/hssf/dev/TestBiffViewer.java b/src/testcases/org/apache/poi/hssf/dev/TestBiffViewer.java index a97aa2ddc..711215d18 100644 --- a/src/testcases/org/apache/poi/hssf/dev/TestBiffViewer.java +++ b/src/testcases/org/apache/poi/hssf/dev/TestBiffViewer.java @@ -1,3 +1,19 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ package org.apache.poi.hssf.dev; import java.io.File; diff --git a/src/testcases/org/apache/poi/hssf/dev/TestEFBiffViewer.java b/src/testcases/org/apache/poi/hssf/dev/TestEFBiffViewer.java index df3efb5ec..174beca38 100644 --- a/src/testcases/org/apache/poi/hssf/dev/TestEFBiffViewer.java +++ b/src/testcases/org/apache/poi/hssf/dev/TestEFBiffViewer.java @@ -1,3 +1,19 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ package org.apache.poi.hssf.dev; import java.io.File; diff --git a/src/testcases/org/apache/poi/hssf/dev/TestFormulaViewer.java b/src/testcases/org/apache/poi/hssf/dev/TestFormulaViewer.java index ec35a4d5d..1ceb55c55 100644 --- a/src/testcases/org/apache/poi/hssf/dev/TestFormulaViewer.java +++ b/src/testcases/org/apache/poi/hssf/dev/TestFormulaViewer.java @@ -1,3 +1,19 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ package org.apache.poi.hssf.dev; import java.io.File; diff --git a/src/testcases/org/apache/poi/hssf/dev/TestReSave.java b/src/testcases/org/apache/poi/hssf/dev/TestReSave.java index 33e4f6aa0..3e0773ee5 100644 --- a/src/testcases/org/apache/poi/hssf/dev/TestReSave.java +++ b/src/testcases/org/apache/poi/hssf/dev/TestReSave.java @@ -1,3 +1,19 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ package org.apache.poi.hssf.dev; import static org.junit.Assert.assertTrue; diff --git a/src/testcases/org/apache/poi/hssf/dev/TestRecordLister.java b/src/testcases/org/apache/poi/hssf/dev/TestRecordLister.java index 405c43f16..58deca919 100644 --- a/src/testcases/org/apache/poi/hssf/dev/TestRecordLister.java +++ b/src/testcases/org/apache/poi/hssf/dev/TestRecordLister.java @@ -1,3 +1,19 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ package org.apache.poi.hssf.dev; import java.io.File; diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestDeltaFunctionsFromSpreadsheet.java b/src/testcases/org/apache/poi/ss/formula/functions/TestDeltaFunctionsFromSpreadsheet.java index 47bea2134..a15cf7cf7 100644 --- a/src/testcases/org/apache/poi/ss/formula/functions/TestDeltaFunctionsFromSpreadsheet.java +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestDeltaFunctionsFromSpreadsheet.java @@ -1,3 +1,19 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ package org.apache.poi.ss.formula.functions; /** From 552d44d96e8b48ccf20d9fbc3cc184a5daa88871 Mon Sep 17 00:00:00 2001 From: Dominik Stadler Date: Mon, 20 Jan 2014 19:25:22 +0000 Subject: [PATCH 03/11] adjust ant-target check-rat: Download jarfile instead of requiring it locally, write report to a temporary file and scan it for failures to break the build if necessary git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1559810 13f79535-47bb-0310-9956-ffa450edef68 --- build.xml | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/build.xml b/build.xml index b4ed5f251..d30bd956c 100644 --- a/build.xml +++ b/build.xml @@ -158,6 +158,10 @@ under the License. + + + + @@ -172,7 +176,6 @@ under the License. - @@ -181,6 +184,10 @@ under the License. + + + + @@ -343,6 +350,7 @@ under the License. + @@ -389,6 +397,10 @@ under the License. + + + + @@ -1345,10 +1357,13 @@ under the License. - + + + - + uri="antlib:org.apache.rat.anttasks" + classpath="${main.lib}/apache-rat-0.10.jar" /> + @@ -1359,6 +1374,12 @@ under the License. + + + ${rat.reportcontent} + + + + - From 802824881b5aba62b4e8649c9d8c7f4d349b5fa9 Mon Sep 17 00:00:00 2001 From: Dominik Stadler Date: Mon, 20 Jan 2014 19:31:57 +0000 Subject: [PATCH 04/11] Add license check via Apache rat to jenkins build git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1559813 13f79535-47bb-0310-9956-ffa450edef68 --- build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.xml b/build.xml index d30bd956c..761ae1de7 100644 --- a/build.xml +++ b/build.xml @@ -1317,7 +1317,7 @@ under the License. - + From c1963d6e60b4d2a82d46e0e111deef0579f68b63 Mon Sep 17 00:00:00 2001 From: Dominik Stadler Date: Mon, 20 Jan 2014 19:55:44 +0000 Subject: [PATCH 05/11] Fix pattern for license check failure git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1559818 13f79535-47bb-0310-9956-ffa450edef68 --- build.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build.xml b/build.xml index 761ae1de7..267203f3e 100644 --- a/build.xml +++ b/build.xml @@ -1379,7 +1379,6 @@ under the License. ${rat.reportcontent} - - + From d2687261e3b3b07b7785a7a81610da34b10964ad Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Thu, 23 Jan 2014 16:43:59 +0000 Subject: [PATCH 06/11] Patch from Detlef Brendle from bug #55873 - Support for COUNTIFS function git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1560736 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/ss/formula/atp/AnalysisToolPak.java | 1 + .../poi/ss/formula/functions/Countifs.java | 56 ++++++++++++++++ .../ss/formula/functions/CountifsTests.java | 66 +++++++++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 src/java/org/apache/poi/ss/formula/functions/Countifs.java create mode 100644 src/testcases/org/apache/poi/ss/formula/functions/CountifsTests.java diff --git a/src/java/org/apache/poi/ss/formula/atp/AnalysisToolPak.java b/src/java/org/apache/poi/ss/formula/atp/AnalysisToolPak.java index 295a056df..d8d8bfad4 100644 --- a/src/java/org/apache/poi/ss/formula/atp/AnalysisToolPak.java +++ b/src/java/org/apache/poi/ss/formula/atp/AnalysisToolPak.java @@ -164,6 +164,7 @@ public final class AnalysisToolPak implements UDFFinder { r(m, "YIELD", null); r(m, "YIELDDISC", null); r(m, "YIELDMAT", null); + r(m, "COUNTIFS", Countifs.instance); return m; } diff --git a/src/java/org/apache/poi/ss/formula/functions/Countifs.java b/src/java/org/apache/poi/ss/formula/functions/Countifs.java new file mode 100644 index 000000000..8fdb4249c --- /dev/null +++ b/src/java/org/apache/poi/ss/formula/functions/Countifs.java @@ -0,0 +1,56 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + + +package org.apache.poi.ss.formula.functions; + +import org.apache.poi.ss.formula.OperationEvaluationContext; +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.ValueEval; + +/** + * Implementation for the function COUNTIFS + *

+ * Syntax: COUNTIFS(criteria_range1, criteria1, [criteria_range2, criteria2]) + *

+ */ + +public class Countifs implements FreeRefFunction { + public static final FreeRefFunction instance = new Countifs(); + + @Override + public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) { + Double result = null; + if (args.length == 0 || args.length % 2 > 0) { + return ErrorEval.VALUE_INVALID; + } + for (int i = 0; i < args.length; ) { + ValueEval firstArg = args[i]; + ValueEval secondArg = args[i + 1]; + i += 2; + NumberEval evaluate = (NumberEval) new Countif().evaluate(new ValueEval[]{firstArg, secondArg}, ec.getRowIndex(), ec.getColumnIndex()); + if (result == null) { + result = evaluate.getNumberValue(); + } else if (evaluate.getNumberValue() < result) { + result = evaluate.getNumberValue(); + } + } + return new NumberEval(result == null ? 0 : result); + } +} + diff --git a/src/testcases/org/apache/poi/ss/formula/functions/CountifsTests.java b/src/testcases/org/apache/poi/ss/formula/functions/CountifsTests.java new file mode 100644 index 000000000..94a5c86e9 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/CountifsTests.java @@ -0,0 +1,66 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + + +package org.apache.poi.ss.formula.functions; + +import junit.framework.TestCase; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.formula.atp.AnalysisToolPak; +import org.apache.poi.ss.usermodel.*; + +public class CountifsTests extends TestCase { + + public void testCallFunction() { + HSSFWorkbook workbook = new HSSFWorkbook(); + Sheet sheet = workbook.createSheet("test"); + Row row1 = sheet.createRow(0); + Cell cellA1 = row1.createCell(0, Cell.CELL_TYPE_FORMULA); + Cell cellB1 = row1.createCell(1, Cell.CELL_TYPE_NUMERIC); + Cell cellC1 = row1.createCell(2, Cell.CELL_TYPE_NUMERIC); + Cell cellD1 = row1.createCell(3, Cell.CELL_TYPE_NUMERIC); + Cell cellE1 = row1.createCell(4, Cell.CELL_TYPE_NUMERIC); + cellB1.setCellValue(1); + cellC1.setCellValue(1); + cellD1.setCellValue(2); + cellE1.setCellValue(4); + + cellA1.setCellFormula("COUNTIFS(B1:C1,1, D1:E1,2)"); + FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator(); + CellValue evaluate = evaluator.evaluate(cellA1); + assertEquals(1.0d, evaluate.getNumberValue()); + } + + public void testCallFunction_invalidArgs() { + HSSFWorkbook workbook = new HSSFWorkbook(); + Sheet sheet = workbook.createSheet("test"); + Row row1 = sheet.createRow(0); + Cell cellA1 = row1.createCell(0, Cell.CELL_TYPE_FORMULA); + cellA1.setCellFormula("COUNTIFS()"); + FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator(); + CellValue evaluate = evaluator.evaluate(cellA1); + assertEquals(15, evaluate.getErrorValue()); + cellA1.setCellFormula("COUNTIFS(A1:C1)"); + evaluator = workbook.getCreationHelper().createFormulaEvaluator(); + evaluate = evaluator.evaluate(cellA1); + assertEquals(15, evaluate.getErrorValue()); + cellA1.setCellFormula("COUNTIFS(A1:C1,2,2)"); + evaluator = workbook.getCreationHelper().createFormulaEvaluator(); + evaluate = evaluator.evaluate(cellA1); + assertEquals(15, evaluate.getErrorValue()); + } +} From 474c4eec6af82d40505014b66e1f48a005d73899 Mon Sep 17 00:00:00 2001 From: Andreas Beeker Date: Sat, 25 Jan 2014 21:56:08 +0000 Subject: [PATCH 07/11] jdk 5 compiler doesn't support overwrite for interfaces ... git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1561406 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/poi/ss/formula/functions/Countifs.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/java/org/apache/poi/ss/formula/functions/Countifs.java b/src/java/org/apache/poi/ss/formula/functions/Countifs.java index 8fdb4249c..95982fe67 100644 --- a/src/java/org/apache/poi/ss/formula/functions/Countifs.java +++ b/src/java/org/apache/poi/ss/formula/functions/Countifs.java @@ -33,7 +33,6 @@ import org.apache.poi.ss.formula.eval.ValueEval; public class Countifs implements FreeRefFunction { public static final FreeRefFunction instance = new Countifs(); - @Override public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) { Double result = null; if (args.length == 0 || args.length % 2 > 0) { From 30d9106d9a79480a83910f6b1f6eab5f2ef6681e Mon Sep 17 00:00:00 2001 From: Andreas Beeker Date: Sun, 26 Jan 2014 02:18:53 +0000 Subject: [PATCH 08/11] - Bug 51585 - WorkbookFactory.create() hangs when creating a workbook - adapted relevant test-classes to Junit4 to support timeout handling - tab / space cleanup git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1561435 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/poi/xssf/usermodel/XSSFSheet.java | 69 ++- .../xssf/usermodel/helpers/ColumnHelper.java | 332 ++++++++------- .../poi/xssf/streaming/TestSXSSFSheet.java | 74 ++-- .../poi/xssf/usermodel/TestXSSFSheet.java | 392 ++++++++++-------- .../poi/hssf/usermodel/TestHSSFSheet.java | 171 +++++--- .../poi/ss/usermodel/BaseTestSheet.java | 229 +++++----- test-data/spreadsheet/51585.xlsx | Bin 0 -> 262225 bytes 7 files changed, 751 insertions(+), 516 deletions(-) create mode 100644 test-data/spreadsheet/51585.xlsx diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java index 1e8b64130..25ffd0243 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java @@ -42,7 +42,16 @@ import org.apache.poi.openxml4j.opc.PackageRelationshipCollection; import org.apache.poi.ss.SpreadsheetVersion; import org.apache.poi.ss.formula.FormulaShifter; import org.apache.poi.ss.formula.SheetNameFormatter; -import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellRange; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.DataValidation; +import org.apache.poi.ss.usermodel.DataValidationHelper; +import org.apache.poi.ss.usermodel.Footer; +import org.apache.poi.ss.usermodel.Header; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddressList; import org.apache.poi.ss.util.CellReference; @@ -58,7 +67,48 @@ import org.apache.poi.xssf.usermodel.helpers.XSSFRowShifter; import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlOptions; import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.*; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTAutoFilter; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBreak; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCalcPr; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellFormula; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTColor; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCommentList; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDataValidation; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDataValidations; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDrawing; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHeaderFooter; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHyperlink; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTLegacyDrawing; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCell; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCells; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTOutlinePr; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageBreak; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageMargins; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageSetUpPr; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPane; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPrintOptions; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSelection; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheet; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetCalcPr; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetFormatPr; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetPr; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetProtection; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetView; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetViews; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTablePart; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableParts; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCalcMode; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellFormulaType; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPane; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPaneState; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.STUnsignedShortHex; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorksheetDocument; /** * High level representation of a SpreadsheetML worksheet. @@ -1206,9 +1256,24 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { private void groupColumn1Based(int fromColumn, int toColumn) { CTCols ctCols=worksheet.getColsArray(0); CTCol ctCol=CTCol.Factory.newInstance(); + + // copy attributes, as they might be removed by merging with the new column + // TODO: check if this fix is really necessary or if the sweeping algorithm + // in addCleanColIntoCols needs to be adapted ... + CTCol fixCol_before = this.columnHelper.getColumn1Based(toColumn, false); + if (fixCol_before != null) { + fixCol_before = (CTCol)fixCol_before.copy(); + } + ctCol.setMin(fromColumn); ctCol.setMax(toColumn); this.columnHelper.addCleanColIntoCols(ctCols, ctCol); + + CTCol fixCol_after = this.columnHelper.getColumn1Based(toColumn, false); + if (fixCol_before != null && fixCol_after != null) { + this.columnHelper.setColumnAttributes(fixCol_before, fixCol_after); + } + for(int index=fromColumn;index<=toColumn;index++){ CTCol col=columnHelper.getColumn1Based(index, false); //col must exist diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/ColumnHelper.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/ColumnHelper.java index c7c565fdc..e8751ef89 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/ColumnHelper.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/ColumnHelper.java @@ -17,13 +17,18 @@ package org.apache.poi.xssf.usermodel.helpers; +import java.util.ArrayList; import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.Comparator; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Set; +import java.util.TreeSet; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.xssf.util.CTColComparator; -import org.apache.poi.xssf.util.NumericRanges; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet; @@ -44,30 +49,114 @@ public class ColumnHelper { this.worksheet = worksheet; cleanColumns(); } - - @SuppressWarnings("deprecation") //YK: getXYZArray() array accessors are deprecated in xmlbeans with JDK 1.5 support + public void cleanColumns() { this.newCols = CTCols.Factory.newInstance(); - CTCols[] colsArray = worksheet.getColsArray(); - int i = 0; - for (i = 0; i < colsArray.length; i++) { - CTCols cols = colsArray[i]; - CTCol[] colArray = cols.getColArray(); - for (int y = 0; y < colArray.length; y++) { - CTCol col = colArray[y]; - newCols = addCleanColIntoCols(newCols, col); + + CTCols aggregateCols = CTCols.Factory.newInstance(); + List colsList = worksheet.getColsList(); + if (colsList != null) { + for (CTCols cols : colsList) { + for (CTCol col : cols.getColList()) { + cloneCol(aggregateCols, col); + } } } + + sortColumns(aggregateCols); + + CTCol[] colArray = new CTCol[aggregateCols.getColList().size()]; + aggregateCols.getColList().toArray(colArray); + sweepCleanColumns(newCols, colArray, null); + + int i = colsList.size(); for (int y = i - 1; y >= 0; y--) { worksheet.removeCols(y); } worksheet.addNewCols(); worksheet.setColsArray(0, newCols); } + + private static class CTColByMaxComparator implements Comparator { + + public int compare(CTCol arg0, CTCol arg1) { + if (arg0.getMax() < arg1.getMax()) { + return -1; + } else { + if (arg0.getMax() > arg1.getMax()) return 1; + else return 0; + } + } + + } + + /** + * @see http://en.wikipedia.org/wiki/Sweep_line_algorithm + */ + private void sweepCleanColumns(CTCols cols, CTCol[] flattenedColsArray, CTCol overrideColumn) { + List flattenedCols = new ArrayList(Arrays.asList(flattenedColsArray)); + TreeSet currentElements = new TreeSet(new CTColByMaxComparator()); + ListIterator flIter = flattenedCols.listIterator(); + CTCol haveOverrideColumn = null; + long lastMaxIndex = 0; + long currentMax = 0; + while (flIter.hasNext()) { + CTCol col = flIter.next(); + long currentIndex = col.getMin(); + long nextIndex = (col.getMax() > currentMax) ? col.getMax() : currentMax; + if (flIter.hasNext()) { + nextIndex = flIter.next().getMin(); + flIter.previous(); + } + Iterator iter = currentElements.iterator(); + while (iter.hasNext()) { + CTCol elem = iter.next(); + if (currentIndex <= elem.getMax()) break; // all passed elements have been purged + iter.remove(); + } + if (!currentElements.isEmpty() && lastMaxIndex < currentIndex) { + // we need to process previous elements first + insertCol(cols, lastMaxIndex, currentIndex - 1, currentElements.toArray(new CTCol[]{}), true, haveOverrideColumn); + } + currentElements.add(col); + if (col.getMax() > currentMax) currentMax = col.getMax(); + if (col.equals(overrideColumn)) haveOverrideColumn = overrideColumn; + while (currentIndex <= nextIndex && !currentElements.isEmpty()) { + Set currentIndexElements = new HashSet(); + CTCol currentElem = currentElements.first(); + long currentElemIndex = currentElem.getMax(); + currentIndexElements.add(currentElem); + while (currentElements.higher(currentElem) != null && currentElements.higher(currentElem).getMax() == currentElemIndex) { + currentElem = currentElements.higher(currentElem); + currentIndexElements.add(currentElem); + if (col.getMax() > currentMax) currentMax = col.getMax(); + if (col.equals(overrideColumn)) haveOverrideColumn = overrideColumn; + } + if (currentElemIndex < nextIndex || !flIter.hasNext()) { + insertCol(cols, currentIndex, currentElemIndex, currentElements.toArray(new CTCol[]{}), true, haveOverrideColumn); + if (flIter.hasNext()) { + if (nextIndex > currentElemIndex) { + currentElements.removeAll(currentIndexElements); + if (currentIndexElements.contains(overrideColumn)) haveOverrideColumn = null; + } + } else { + currentElements.removeAll(currentIndexElements); + if (currentIndexElements.contains(overrideColumn)) haveOverrideColumn = null; + } + lastMaxIndex = currentIndex = currentElemIndex + 1; + } else { + lastMaxIndex = currentIndex; + currentIndex = nextIndex + 1; + } + + } + } + sortColumns(cols); + } - @SuppressWarnings("deprecation") //YK: getXYZArray() array accessors are deprecated in xmlbeans with JDK 1.5 support public static void sortColumns(CTCols newCols) { - CTCol[] colArray = newCols.getColArray(); + CTCol[] colArray = new CTCol[newCols.getColList().size()]; + newCols.getColList().toArray(colArray); Arrays.sort(colArray, new CTColComparator()); newCols.setColArray(colArray); } @@ -84,8 +173,9 @@ public class ColumnHelper { * Returns the Column at the given 0 based index */ public CTCol getColumn(long index, boolean splitColumns) { - return getColumn1Based(index+1, splitColumns); + return getColumn1Based(index+1, splitColumns); } + /** * Returns the Column at the given 1 based index. * POI default is 0 based, but the file stores @@ -93,119 +183,61 @@ public class ColumnHelper { */ public CTCol getColumn1Based(long index1, boolean splitColumns) { CTCols colsArray = worksheet.getColsArray(0); - for (int i = 0; i < colsArray.sizeOfColArray(); i++) { + for (int i = 0; i < colsArray.sizeOfColArray(); i++) { CTCol colArray = colsArray.getColArray(i); - if (colArray.getMin() <= index1 && colArray.getMax() >= index1) { - if (splitColumns) { - if (colArray.getMin() < index1) { - insertCol(colsArray, colArray.getMin(), (index1 - 1), new CTCol[]{colArray}); - } - if (colArray.getMax() > index1) { - insertCol(colsArray, (index1 + 1), colArray.getMax(), new CTCol[]{colArray}); - } - colArray.setMin(index1); - colArray.setMax(index1); - } + if (colArray.getMin() <= index1 && colArray.getMax() >= index1) { + if (splitColumns) { + if (colArray.getMin() < index1) { + insertCol(colsArray, colArray.getMin(), (index1 - 1), new CTCol[]{colArray}); + } + if (colArray.getMax() > index1) { + insertCol(colsArray, (index1 + 1), colArray.getMax(), new CTCol[]{colArray}); + } + colArray.setMin(index1); + colArray.setMax(index1); + } return colArray; } } return null; } - + public CTCols addCleanColIntoCols(CTCols cols, CTCol col) { - boolean colOverlaps = false; - // a Map to remember overlapping columns - Map overlappingCols = new LinkedHashMap(); - int sizeOfColArray = cols.sizeOfColArray(); - for (int i = 0; i < sizeOfColArray; i++) { - CTCol ithCol = cols.getColArray(i); - long[] range1 = { ithCol.getMin(), ithCol.getMax() }; - long[] range2 = { col.getMin(), col.getMax() }; - long[] overlappingRange = NumericRanges.getOverlappingRange(range1, - range2); - int overlappingType = NumericRanges.getOverlappingType(range1, - range2); - // different behavior required for each of the 4 different - // overlapping types - if (overlappingType == NumericRanges.OVERLAPS_1_MINOR) { - // move the max border of the ithCol - // and insert a new column within the overlappingRange with merged column attributes - ithCol.setMax(overlappingRange[0] - 1); - insertCol(cols, overlappingRange[0], - overlappingRange[1], new CTCol[] { ithCol, col }); - i++; - } else if (overlappingType == NumericRanges.OVERLAPS_2_MINOR) { - // move the min border of the ithCol - // and insert a new column within the overlappingRange with merged column attributes - ithCol.setMin(overlappingRange[1] + 1); - insertCol(cols, overlappingRange[0], - overlappingRange[1], new CTCol[] { ithCol, col }); - i++; - } else if (overlappingType == NumericRanges.OVERLAPS_2_WRAPS) { - // merge column attributes, no new column is needed - setColumnAttributes(col, ithCol); - } else if (overlappingType == NumericRanges.OVERLAPS_1_WRAPS) { - // split the ithCol in three columns: before the overlappingRange, overlappingRange, and after the overlappingRange - // before overlappingRange - if (col.getMin() != ithCol.getMin()) { - insertCol(cols, ithCol.getMin(), (col - .getMin() - 1), new CTCol[] { ithCol }); - i++; - } - // after the overlappingRange - if (col.getMax() != ithCol.getMax()) { - insertCol(cols, (col.getMax() + 1), - ithCol.getMax(), new CTCol[] { ithCol }); - i++; - } - // within the overlappingRange - ithCol.setMin(overlappingRange[0]); - ithCol.setMax(overlappingRange[1]); - setColumnAttributes(col, ithCol); - } - if (overlappingType != NumericRanges.NO_OVERLAPS) { - colOverlaps = true; - // remember overlapped columns - for (long j = overlappingRange[0]; j <= overlappingRange[1]; j++) { - overlappingCols.put(Long.valueOf(j), Boolean.TRUE); - } - } + CTCols newCols = CTCols.Factory.newInstance(); + for (CTCol c : cols.getColList()) { + cloneCol(newCols, c); } - if (!colOverlaps) { - cloneCol(cols, col); - } else { - // insert new columns for ranges without overlaps - long colMin = -1; - for (long j = col.getMin(); j <= col.getMax(); j++) { - if (!Boolean.TRUE.equals(overlappingCols.get(Long.valueOf(j)))) { - if (colMin < 0) { - colMin = j; - } - if ((j + 1) > col.getMax() || Boolean.TRUE.equals(overlappingCols.get(Long.valueOf(j + 1)))) { - insertCol(cols, colMin, j, new CTCol[] { col }); - colMin = -1; - } - } - } - } - sortColumns(cols); - return cols; + cloneCol(newCols, col); + sortColumns(newCols); + CTCol[] colArray = new CTCol[newCols.getColList().size()]; + newCols.getColList().toArray(colArray); + CTCols returnCols = CTCols.Factory.newInstance(); + sweepCleanColumns(returnCols, colArray, col); + colArray = new CTCol[returnCols.getColList().size()]; + returnCols.getColList().toArray(colArray); + cols.setColArray(colArray); + return returnCols; } /* * Insert a new CTCol at position 0 into cols, setting min=min, max=max and * copying all the colsWithAttributes array cols attributes into newCol */ + private CTCol insertCol(CTCols cols, long min, long max, CTCol[] colsWithAttributes) { + return insertCol(cols, min, max, colsWithAttributes, false, null); + } + private CTCol insertCol(CTCols cols, long min, long max, - CTCol[] colsWithAttributes) { - if(!columnExists(cols,min,max)){ - CTCol newCol = cols.insertNewCol(0); - newCol.setMin(min); - newCol.setMax(max); - for (CTCol col : colsWithAttributes) { - setColumnAttributes(col, newCol); - } - return newCol; + CTCol[] colsWithAttributes, boolean ignoreExistsCheck, CTCol overrideColumn) { + if(ignoreExistsCheck || !columnExists(cols,min,max)){ + CTCol newCol = cols.insertNewCol(0); + newCol.setMin(min); + newCol.setMax(max); + for (CTCol col : colsWithAttributes) { + setColumnAttributes(col, newCol); + } + if (overrideColumn != null) setColumnAttributes(overrideColumn, newCol); + return newCol; } return null; } @@ -215,7 +247,7 @@ public class ColumnHelper { * in the supplied list of column definitions? */ public boolean columnExists(CTCols cols, long index) { - return columnExists1Based(cols, index+1); + return columnExists1Based(cols, index+1); } private boolean columnExists1Based(CTCols cols, long index1) { for (int i = 0; i < cols.sizeOfColArray(); i++) { @@ -227,7 +259,7 @@ public class ColumnHelper { } public void setColumnAttributes(CTCol fromCol, CTCol toCol) { - if(fromCol.isSetBestFit()) toCol.setBestFit(fromCol.getBestFit()); + if(fromCol.isSetBestFit()) toCol.setBestFit(fromCol.getBestFit()); if(fromCol.isSetCustomWidth()) toCol.setCustomWidth(fromCol.getCustomWidth()); if(fromCol.isSetHidden()) toCol.setHidden(fromCol.getHidden()); if(fromCol.isSetStyle()) toCol.setStyle(fromCol.getStyle()); @@ -271,38 +303,38 @@ public class ColumnHelper { return col; } - public void setColDefaultStyle(long index, CellStyle style) { - setColDefaultStyle(index, style.getIndex()); - } - - public void setColDefaultStyle(long index, int styleId) { - CTCol col = getOrCreateColumn1Based(index+1, true); - col.setStyle(styleId); - } - - // Returns -1 if no column is found for the given index - public int getColDefaultStyle(long index) { - if (getColumn(index, false) != null) { - return (int) getColumn(index, false).getStyle(); - } - return -1; - } + public void setColDefaultStyle(long index, CellStyle style) { + setColDefaultStyle(index, style.getIndex()); + } + + public void setColDefaultStyle(long index, int styleId) { + CTCol col = getOrCreateColumn1Based(index+1, true); + col.setStyle(styleId); + } + + // Returns -1 if no column is found for the given index + public int getColDefaultStyle(long index) { + if (getColumn(index, false) != null) { + return (int) getColumn(index, false).getStyle(); + } + return -1; + } - private boolean columnExists(CTCols cols, long min, long max) { - for (int i = 0; i < cols.sizeOfColArray(); i++) { - if (cols.getColArray(i).getMin() == min && cols.getColArray(i).getMax() == max) { - return true; - } - } - return false; - } - - public int getIndexOfColumn(CTCols cols, CTCol col) { - for (int i = 0; i < cols.sizeOfColArray(); i++) { - if (cols.getColArray(i).getMin() == col.getMin() && cols.getColArray(i).getMax() == col.getMax()) { - return i; - } - } - return -1; - } -} + private boolean columnExists(CTCols cols, long min, long max) { + for (int i = 0; i < cols.sizeOfColArray(); i++) { + if (cols.getColArray(i).getMin() == min && cols.getColArray(i).getMax() == max) { + return true; + } + } + return false; + } + + public int getIndexOfColumn(CTCols cols, CTCol col) { + for (int i = 0; i < cols.sizeOfColArray(); i++) { + if (cols.getColArray(i).getMin() == col.getMin() && cols.getColArray(i).getMax() == col.getMax()) { + return i; + } + } + return -1; + } +} \ No newline at end of file diff --git a/src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFSheet.java b/src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFSheet.java index 2da1b4a0a..f4d7781b1 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFSheet.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFSheet.java @@ -19,11 +19,16 @@ package org.apache.poi.xssf.streaming; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + import org.apache.poi.ss.usermodel.BaseTestSheet; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.xssf.SXSSFITestDataProvider; import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.junit.After; +import org.junit.Test; public class TestSXSSFSheet extends BaseTestSheet { @@ -33,7 +38,7 @@ public class TestSXSSFSheet extends BaseTestSheet { } - @Override + @After public void tearDown(){ SXSSFITestDataProvider.instance.cleanup(); } @@ -43,35 +48,30 @@ public class TestSXSSFSheet extends BaseTestSheet { * cloning of sheets is not supported in SXSSF */ @Override - public void testCloneSheet() { - try { - super.testCloneSheet(); - fail("expected exception"); - } catch (RuntimeException e){ - assertEquals("NotImplemented", e.getMessage()); - } + @Test + public void cloneSheet() { + thrown.expect(RuntimeException.class); + thrown.expectMessage("NotImplemented"); + super.cloneSheet(); } @Override - public void testCloneSheetMultipleTimes() { - try { - super.testCloneSheetMultipleTimes(); - fail("expected exception"); - } catch (RuntimeException e){ - assertEquals("NotImplemented", e.getMessage()); - } + @Test + public void cloneSheetMultipleTimes() { + thrown.expect(RuntimeException.class); + thrown.expectMessage("NotImplemented"); + super.cloneSheetMultipleTimes(); } + /** * shifting rows is not supported in SXSSF */ @Override - public void testShiftMerged(){ - try { - super.testShiftMerged(); - fail("expected exception"); - } catch (RuntimeException e){ - assertEquals("NotImplemented", e.getMessage()); - } + @Test + public void shiftMerged(){ + thrown.expect(RuntimeException.class); + thrown.expectMessage("NotImplemented"); + super.shiftMerged(); } /** @@ -80,21 +80,21 @@ public class TestSXSSFSheet extends BaseTestSheet { * The test is disabled because cloning of sheets is not supported in SXSSF */ @Override - public void test35084(){ - try { - super.test35084(); - fail("expected exception"); - } catch (RuntimeException e){ - assertEquals("NotImplemented", e.getMessage()); - } + @Test + public void bug35084(){ + thrown.expect(RuntimeException.class); + thrown.expectMessage("NotImplemented"); + super.bug35084(); } @Override - public void testDefaultColumnStyle() { + @Test + public void defaultColumnStyle() { //TODO column styles are not yet supported by XSSF } - public void testOverrideFlushedRows() { + @Test + public void overrideFlushedRows() { Workbook wb = new SXSSFWorkbook(3); Sheet sheet = wb.createSheet(); @@ -102,16 +102,14 @@ public class TestSXSSFSheet extends BaseTestSheet { sheet.createRow(2); sheet.createRow(3); sheet.createRow(4); - try { - sheet.createRow(1); - fail("expected exception"); - } catch (Throwable e){ - assertEquals("Attempting to write a row[1] in the range [0,1] that is already written to disk.", e.getMessage()); - } + thrown.expect(Throwable.class); + thrown.expectMessage("Attempting to write a row[1] in the range [0,1] that is already written to disk."); + sheet.createRow(1); } - public void testOverrideRowsInTemplate() { + @Test + public void overrideRowsInTemplate() { XSSFWorkbook template = new XSSFWorkbook(); template.createSheet().createRow(1); diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java index 329283cc3..b9c2a4466 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java @@ -17,6 +17,15 @@ package org.apache.poi.xssf.usermodel; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.util.List; import org.apache.poi.hssf.HSSFTestDataSamples; @@ -39,10 +48,21 @@ import org.apache.poi.xssf.model.StylesTable; import org.apache.poi.xssf.streaming.SXSSFSheet; import org.apache.poi.xssf.streaming.SXSSFWorkbook; import org.apache.poi.xssf.usermodel.helpers.ColumnHelper; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.*; +import org.junit.Test; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCalcPr; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComments; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetData; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetProtection; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTXf; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCalcMode; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPane; -@SuppressWarnings("deprecation") //YK: getXYZArray() array accessors are deprecated in xmlbeans with JDK 1.5 support public final class TestXSSFSheet extends BaseTestSheet { private static final int ROW_COUNT = 40000; @@ -52,16 +72,18 @@ public final class TestXSSFSheet extends BaseTestSheet { } //TODO column styles are not yet supported by XSSF - @Override - public void testDefaultColumnStyle() { - //super.testDefaultColumnStyle(); + @Test + public void defaultColumnStyle() { + //super.defaultColumnStyle(); } - public void testTestGetSetMargin() { + @Test + public void getSetMargin() { baseTestGetSetMargin(new double[]{0.7, 0.7, 0.75, 0.75, 0.3, 0.3}); } - public void testExistingHeaderFooter() { + @Test + public void existingHeaderFooter() { XSSFWorkbook workbook = XSSFTestDataSamples.openSampleWorkbook("45540_classic_Header.xlsx"); XSSFOddHeader hdr; XSSFOddFooter ftr; @@ -117,7 +139,8 @@ public final class TestXSSFSheet extends BaseTestSheet { assertEquals("", ftr.getRight()); } - public void testGetAllHeadersFooters() { + @Test + public void getAllHeadersFooters() { XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet("Sheet 1"); assertNotNull(sheet.getOddFooter()); @@ -156,7 +179,8 @@ public final class TestXSSFSheet extends BaseTestSheet { assertEquals("odd header center", sheet.getHeader().getCenter()); } - public void testAutoSizeColumn() { + @Test + public void autoSizeColumn() { XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet("Sheet 1"); sheet.createRow(0).createCell(13).setCellValue("test"); @@ -171,7 +195,8 @@ public final class TestXSSFSheet extends BaseTestSheet { /** * XSSFSheet autoSizeColumn() on empty RichTextString fails */ - public void test48325() { + @Test + public void bug48325() { XSSFWorkbook wb = new XSSFWorkbook(); XSSFSheet sheet = wb.createSheet("Test"); CreationHelper factory = wb.getCreationHelper(); @@ -187,7 +212,8 @@ public final class TestXSSFSheet extends BaseTestSheet { sheet.autoSizeColumn(0); } - public void testGetCellComment() { + @Test + public void getCellComment() { XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet(); XSSFDrawing dg = sheet.createDrawingPatriarch(); @@ -200,7 +226,8 @@ public final class TestXSSFSheet extends BaseTestSheet { assertEquals("test C10 author", sheet.getCellComment(9, 2).getAuthor()); } - public void testSetCellComment() { + @Test + public void setCellComment() { XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet(); @@ -217,7 +244,8 @@ public final class TestXSSFSheet extends BaseTestSheet { assertEquals("test A1 author", comments.getAuthor((int) ctComments.getCommentList().getCommentArray(0).getAuthorId())); } - public void testGetActiveCell() { + @Test + public void getActiveCell() { XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet(); sheet.setActiveCell("R5"); @@ -226,7 +254,8 @@ public final class TestXSSFSheet extends BaseTestSheet { } - public void testCreateFreezePane_XSSF() { + @Test + public void createFreezePane_XSSF() { XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet(); CTWorksheet ctWorksheet = sheet.getCTWorksheet(); @@ -243,7 +272,8 @@ public final class TestXSSFSheet extends BaseTestSheet { assertEquals(STPane.BOTTOM_RIGHT, ctWorksheet.getSheetViews().getSheetViewArray(0).getPane().getActivePane()); } - public void testNewMergedRegionAt() { + @Test + public void newMergedRegionAt() { XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet(); CellRangeAddress region = CellRangeAddress.valueOf("B2:D4"); @@ -252,7 +282,8 @@ public final class TestXSSFSheet extends BaseTestSheet { assertEquals(1, sheet.getNumMergedRegions()); } - public void testRemoveMergedRegion_lowlevel() { + @Test + public void removeMergedRegion_lowlevel() { XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet(); CTWorksheet ctWorksheet = sheet.getCTWorksheet(); @@ -274,7 +305,8 @@ public final class TestXSSFSheet extends BaseTestSheet { "region on the sheet.", sheet.getCTWorksheet().getMergeCells()); } - public void testSetDefaultColumnStyle() { + @Test + public void setDefaultColumnStyle() { XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet(); CTWorksheet ctWorksheet = sheet.getCTWorksheet(); @@ -299,7 +331,8 @@ public final class TestXSSFSheet extends BaseTestSheet { } - public void testGroupUngroupColumn() { + @Test + public void groupUngroupColumn() { XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet(); @@ -308,41 +341,41 @@ public final class TestXSSFSheet extends BaseTestSheet { sheet.groupColumn(10, 11); CTCols cols = sheet.getCTWorksheet().getColsArray(0); assertEquals(2, cols.sizeOfColArray()); - CTCol[] colArray = cols.getColArray(); + List colArray = cols.getColList(); assertNotNull(colArray); - assertEquals(2 + 1, colArray[0].getMin()); // 1 based - assertEquals(7 + 1, colArray[0].getMax()); // 1 based - assertEquals(1, colArray[0].getOutlineLevel()); + assertEquals(2 + 1, colArray.get(0).getMin()); // 1 based + assertEquals(7 + 1, colArray.get(0).getMax()); // 1 based + assertEquals(1, colArray.get(0).getOutlineLevel()); //two level sheet.groupColumn(1, 2); cols = sheet.getCTWorksheet().getColsArray(0); assertEquals(4, cols.sizeOfColArray()); - colArray = cols.getColArray(); - assertEquals(2, colArray[1].getOutlineLevel()); + colArray = cols.getColList(); + assertEquals(2, colArray.get(1).getOutlineLevel()); //three level sheet.groupColumn(6, 8); sheet.groupColumn(2, 3); cols = sheet.getCTWorksheet().getColsArray(0); assertEquals(7, cols.sizeOfColArray()); - colArray = cols.getColArray(); - assertEquals(3, colArray[1].getOutlineLevel()); + colArray = cols.getColList(); + assertEquals(3, colArray.get(1).getOutlineLevel()); assertEquals(3, sheet.getCTWorksheet().getSheetFormatPr().getOutlineLevelCol()); sheet.ungroupColumn(8, 10); - colArray = cols.getColArray(); + colArray = cols.getColList(); //assertEquals(3, colArray[1].getOutlineLevel()); sheet.ungroupColumn(4, 6); sheet.ungroupColumn(2, 2); - colArray = cols.getColArray(); - assertEquals(4, colArray.length); + colArray = cols.getColList(); + assertEquals(4, colArray.size()); assertEquals(2, sheet.getCTWorksheet().getSheetFormatPr().getOutlineLevelCol()); } - - public void testGroupUngroupRow() { + @Test + public void groupUngroupRow() { XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet(); @@ -376,7 +409,8 @@ public final class TestXSSFSheet extends BaseTestSheet { assertEquals(1, sheet.getCTWorksheet().getSheetFormatPr().getOutlineLevelRow()); } - public void testSetZoom() { + @Test + public void setZoom() { XSSFWorkbook workBook = new XSSFWorkbook(); XSSFSheet sheet1 = workBook.createSheet("new sheet"); sheet1.setZoom(3, 4); // 75 percent magnification @@ -401,7 +435,8 @@ public final class TestXSSFSheet extends BaseTestSheet { * be doing... Someone who understands the goals a little * better should really review this! */ - public void testSetColumnGroupCollapsed(){ + @Test + public void setColumnGroupCollapsed(){ Workbook wb = new XSSFWorkbook(); XSSFSheet sheet1 =(XSSFSheet) wb.createSheet(); @@ -501,7 +536,7 @@ public final class TestXSSFSheet extends BaseTestSheet { assertEquals(5, cols.getColArray(0).getMin()); // 1 based assertEquals(8, cols.getColArray(0).getMax()); // 1 based assertEquals(false,cols.getColArray(1).isSetHidden()); - assertEquals(false,cols.getColArray(1).isSetCollapsed()); + assertEquals(true,cols.getColArray(1).isSetCollapsed()); assertEquals(9, cols.getColArray(1).getMin()); // 1 based assertEquals(9, cols.getColArray(1).getMax()); // 1 based assertEquals(true, cols.getColArray(2).isSetHidden()); @@ -536,7 +571,7 @@ public final class TestXSSFSheet extends BaseTestSheet { assertEquals(5, cols.getColArray(0).getMin()); // 1 based assertEquals(8, cols.getColArray(0).getMax()); // 1 based assertEquals(false,cols.getColArray(1).isSetHidden()); - assertEquals(false,cols.getColArray(1).isSetCollapsed()); + assertEquals(true,cols.getColArray(1).isSetCollapsed()); assertEquals(9, cols.getColArray(1).getMin()); // 1 based assertEquals(9, cols.getColArray(1).getMax()); // 1 based assertEquals(false,cols.getColArray(2).isSetHidden()); @@ -565,7 +600,7 @@ public final class TestXSSFSheet extends BaseTestSheet { assertEquals(5, cols.getColArray(0).getMin()); // 1 based assertEquals(8, cols.getColArray(0).getMax()); // 1 based assertEquals(false,cols.getColArray(1).isSetHidden()); - assertEquals(false,cols.getColArray(1).isSetCollapsed()); + assertEquals(true,cols.getColArray(1).isSetCollapsed()); assertEquals(9, cols.getColArray(1).getMin()); // 1 based assertEquals(9, cols.getColArray(1).getMax()); // 1 based assertEquals(false,cols.getColArray(2).isSetHidden()); @@ -604,7 +639,7 @@ public final class TestXSSFSheet extends BaseTestSheet { assertEquals(5, cols.getColArray(0).getMin()); // 1 based assertEquals(8, cols.getColArray(0).getMax()); // 1 based assertEquals(false,cols.getColArray(1).isSetHidden()); - assertEquals(false,cols.getColArray(1).isSetCollapsed()); + assertEquals(true,cols.getColArray(1).isSetCollapsed()); assertEquals(9, cols.getColArray(1).getMin()); // 1 based assertEquals(9, cols.getColArray(1).getMax()); // 1 based assertEquals(false,cols.getColArray(2).isSetHidden()); @@ -631,7 +666,8 @@ public final class TestXSSFSheet extends BaseTestSheet { * be doing... Someone who understands the goals a little * better should really review this! */ - public void testSetRowGroupCollapsed(){ + @Test + public void setRowGroupCollapsed(){ Workbook wb = new XSSFWorkbook(); XSSFSheet sheet1 = (XSSFSheet)wb.createSheet(); @@ -707,7 +743,8 @@ public final class TestXSSFSheet extends BaseTestSheet { /** * Get / Set column width and check the actual values of the underlying XML beans */ - public void testColumnWidth_lowlevel() { + @Test + public void columnWidth_lowlevel() { XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet("Sheet 1"); sheet.setColumnWidth(1, 22 * 256); @@ -718,9 +755,9 @@ public final class TestXSSFSheet extends BaseTestSheet { XSSFSheet xs = sheet; CTWorksheet cts = xs.getCTWorksheet(); - CTCols[] cols_s = cts.getColsArray(); - assertEquals(1, cols_s.length); - CTCols cols = cols_s[0]; + List cols_s = cts.getColsList(); + assertEquals(1, cols_s.size()); + CTCols cols = cols_s.get(0); assertEquals(1, cols.sizeOfColArray()); CTCol col = cols.getColArray(0); @@ -733,9 +770,9 @@ public final class TestXSSFSheet extends BaseTestSheet { // Now set another sheet.setColumnWidth(3, 33 * 256); - cols_s = cts.getColsArray(); - assertEquals(1, cols_s.length); - cols = cols_s[0]; + cols_s = cts.getColsList(); + assertEquals(1, cols_s.size()); + cols = cols_s.get(0); assertEquals(2, cols.sizeOfColArray()); col = cols.getColArray(0); @@ -754,7 +791,8 @@ public final class TestXSSFSheet extends BaseTestSheet { /** * Setting width of a column included in a column span */ - public void test47862() { + @Test + public void bug47862() { XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("47862.xlsx"); XSSFSheet sheet = wb.getSheetAt(0); CTCols cols = sheet.getCTWorksheet().getColsArray(0); @@ -810,7 +848,8 @@ public final class TestXSSFSheet extends BaseTestSheet { /** * Hiding a column included in a column span */ - public void test47804() { + @Test + public void bug47804() { XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("47804.xlsx"); XSSFSheet sheet = wb.getSheetAt(0); CTCols cols = sheet.getCTWorksheet().getColsArray(0); @@ -877,7 +916,8 @@ public final class TestXSSFSheet extends BaseTestSheet { assertFalse(sheet.isColumnHidden(5)); } - public void testCommentsTable() { + @Test + public void commentsTable() { XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet1 = workbook.createSheet(); CommentsTable comment1 = sheet1.getCommentsTable(false); @@ -916,7 +956,8 @@ public final class TestXSSFSheet extends BaseTestSheet { * Rows and cells can be created in random order, * but CTRows are kept in ascending order */ - public void testCreateRowA() { + @Test + public void createRow() { XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet(); CTWorksheet wsh = sheet.getCTWorksheet(); @@ -939,27 +980,27 @@ public final class TestXSSFSheet extends BaseTestSheet { row3.createCell(5); - CTRow[] xrow = sheetData.getRowArray(); - assertEquals(3, xrow.length); + List xrow = sheetData.getRowList(); + assertEquals(3, xrow.size()); //rows are sorted: {0, 1, 2} - assertEquals(4, xrow[0].sizeOfCArray()); - assertEquals(1, xrow[0].getR()); - assertTrue(xrow[0].equals(row3.getCTRow())); + assertEquals(4, xrow.get(0).sizeOfCArray()); + assertEquals(1, xrow.get(0).getR()); + assertTrue(xrow.get(0).equals(row3.getCTRow())); - assertEquals(3, xrow[1].sizeOfCArray()); - assertEquals(2, xrow[1].getR()); - assertTrue(xrow[1].equals(row2.getCTRow())); + assertEquals(3, xrow.get(1).sizeOfCArray()); + assertEquals(2, xrow.get(1).getR()); + assertTrue(xrow.get(1).equals(row2.getCTRow())); - assertEquals(2, xrow[2].sizeOfCArray()); - assertEquals(3, xrow[2].getR()); - assertTrue(xrow[2].equals(row1.getCTRow())); + assertEquals(2, xrow.get(2).sizeOfCArray()); + assertEquals(3, xrow.get(2).getR()); + assertTrue(xrow.get(2).equals(row1.getCTRow())); - CTCell[] xcell = xrow[0].getCArray(); - assertEquals("D1", xcell[0].getR()); - assertEquals("A1", xcell[1].getR()); - assertEquals("C1", xcell[2].getR()); - assertEquals("F1", xcell[3].getR()); + List xcell = xrow.get(0).getCList(); + assertEquals("D1", xcell.get(0).getR()); + assertEquals("A1", xcell.get(1).getR()); + assertEquals("C1", xcell.get(2).getR()); + assertEquals("F1", xcell.get(3).getR()); //re-creating a row does NOT add extra data to the parent row2 = sheet.createRow(1); @@ -971,29 +1012,30 @@ public final class TestXSSFSheet extends BaseTestSheet { workbook = XSSFTestDataSamples.writeOutAndReadBack(workbook); sheet = workbook.getSheetAt(0); wsh = sheet.getCTWorksheet(); - xrow = sheetData.getRowArray(); - assertEquals(3, xrow.length); + xrow = sheetData.getRowList(); + assertEquals(3, xrow.size()); //rows are sorted: {0, 1, 2} - assertEquals(4, xrow[0].sizeOfCArray()); - assertEquals(1, xrow[0].getR()); + assertEquals(4, xrow.get(0).sizeOfCArray()); + assertEquals(1, xrow.get(0).getR()); //cells are now sorted - xcell = xrow[0].getCArray(); - assertEquals("A1", xcell[0].getR()); - assertEquals("C1", xcell[1].getR()); - assertEquals("D1", xcell[2].getR()); - assertEquals("F1", xcell[3].getR()); + xcell = xrow.get(0).getCList(); + assertEquals("A1", xcell.get(0).getR()); + assertEquals("C1", xcell.get(1).getR()); + assertEquals("D1", xcell.get(2).getR()); + assertEquals("F1", xcell.get(3).getR()); - assertEquals(0, xrow[1].sizeOfCArray()); - assertEquals(2, xrow[1].getR()); + assertEquals(0, xrow.get(1).sizeOfCArray()); + assertEquals(2, xrow.get(1).getR()); - assertEquals(2, xrow[2].sizeOfCArray()); - assertEquals(3, xrow[2].getR()); + assertEquals(2, xrow.get(2).sizeOfCArray()); + assertEquals(3, xrow.get(2).getR()); } - public void testSetAutoFilter() { + @Test + public void setAutoFilter() { XSSFWorkbook wb = new XSSFWorkbook(); XSSFSheet sheet = wb.createSheet("new sheet"); sheet.setAutoFilter(CellRangeAddress.valueOf("A1:D100")); @@ -1010,10 +1052,10 @@ public final class TestXSSFSheet extends BaseTestSheet { assertEquals("'new sheet'!$A$1:$D$100", nm.getCTName().getStringValue()); } - public void testProtectSheet_lowlevel() { - - XSSFWorkbook wb = new XSSFWorkbook(); - XSSFSheet sheet = wb.createSheet(); + @Test + public void protectSheet_lowlevel() { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = wb.createSheet(); CTSheetProtection pr = sheet.getCTWorksheet().getSheetProtection(); assertNull("CTSheetProtection should be null by default", pr); String password = "Test"; @@ -1031,7 +1073,8 @@ public final class TestXSSFSheet extends BaseTestSheet { } - public void test49966() { + @Test + public void bug49966() { XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("49966.xlsx"); CalculationChain calcChain = wb.getCalculationChain(); assertNotNull(wb.getCalculationChain()); @@ -1053,14 +1096,15 @@ public final class TestXSSFSheet extends BaseTestSheet { /** * See bug #50829 */ - public void testTables() { + @Test + public void tables() { XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("WithTable.xlsx"); assertEquals(3, wb.getNumberOfSheets()); // Check the table sheet XSSFSheet s1 = wb.getSheetAt(0); assertEquals("a", s1.getRow(0).getCell(0).getRichStringCellValue().toString()); - assertEquals(1.0, s1.getRow(1).getCell(0).getNumericCellValue()); + assertEquals(1.0, s1.getRow(1).getCell(0).getNumericCellValue(), 0); List tables = s1.getTables(); assertNotNull(tables); @@ -1080,7 +1124,8 @@ public final class TestXSSFSheet extends BaseTestSheet { /** * Test to trigger OOXML-LITE generating to include org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetCalcPr */ - public void testSetForceFormulaRecalculation() { + @Test + public void setForceFormulaRecalculation() { XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet("Sheet 1"); @@ -1103,104 +1148,107 @@ public final class TestXSSFSheet extends BaseTestSheet { workbook = XSSFTestDataSamples.writeOutAndReadBack(workbook); sheet = workbook.getSheet("Sheet 1"); assertEquals(false, sheet.getForceFormulaRecalculation()); - } - - public void test54607() { - // run with the file provided in the Bug-Report - runGetTopRow("54607.xlsx", true, 1, 0, 0); - runGetLeftCol("54607.xlsx", true, 0, 0, 0); - - // run with some other flie to see - runGetTopRow("54436.xlsx", true, 0); - runGetLeftCol("54436.xlsx", true, 0); - runGetTopRow("TwoSheetsNoneHidden.xlsx", true, 0, 0); - runGetLeftCol("TwoSheetsNoneHidden.xlsx", true, 0, 0); - runGetTopRow("TwoSheetsNoneHidden.xls", false, 0, 0); - runGetLeftCol("TwoSheetsNoneHidden.xls", false, 0, 0); } - private void runGetTopRow(String file, boolean isXSSF, int... topRows) { - final Workbook wb; - if(isXSSF) { - wb = XSSFTestDataSamples.openSampleWorkbook(file); - } else { - wb = HSSFTestDataSamples.openSampleWorkbook(file); - } - for (int si = 0; si < wb.getNumberOfSheets(); si++) { - Sheet sh = wb.getSheetAt(si); - assertNotNull(sh.getSheetName()); - assertEquals("Did not match for sheet " + si, topRows[si], sh.getTopRow()); - } + @Test + public void bug54607() { + // run with the file provided in the Bug-Report + runGetTopRow("54607.xlsx", true, 1, 0, 0); + runGetLeftCol("54607.xlsx", true, 0, 0, 0); - // for XSSF also test with SXSSF - if(isXSSF) { - Workbook swb = new SXSSFWorkbook((XSSFWorkbook) wb); - for (int si = 0; si < swb.getNumberOfSheets(); si++) { - Sheet sh = swb.getSheetAt(si); - assertNotNull(sh.getSheetName()); - assertEquals("Did not match for sheet " + si, topRows[si], sh.getTopRow()); - } - } - } + // run with some other flie to see + runGetTopRow("54436.xlsx", true, 0); + runGetLeftCol("54436.xlsx", true, 0); + runGetTopRow("TwoSheetsNoneHidden.xlsx", true, 0, 0); + runGetLeftCol("TwoSheetsNoneHidden.xlsx", true, 0, 0); + runGetTopRow("TwoSheetsNoneHidden.xls", false, 0, 0); + runGetLeftCol("TwoSheetsNoneHidden.xls", false, 0, 0); + } - private void runGetLeftCol(String file, boolean isXSSF, int... topRows) { - final Workbook wb; - if(isXSSF) { - wb = XSSFTestDataSamples.openSampleWorkbook(file); - } else { - wb = HSSFTestDataSamples.openSampleWorkbook(file); - } - for (int si = 0; si < wb.getNumberOfSheets(); si++) { - Sheet sh = wb.getSheetAt(si); - assertNotNull(sh.getSheetName()); - assertEquals("Did not match for sheet " + si, topRows[si], sh.getLeftCol()); - } + private void runGetTopRow(String file, boolean isXSSF, int... topRows) { + final Workbook wb; + if(isXSSF) { + wb = XSSFTestDataSamples.openSampleWorkbook(file); + } else { + wb = HSSFTestDataSamples.openSampleWorkbook(file); + } + for (int si = 0; si < wb.getNumberOfSheets(); si++) { + Sheet sh = wb.getSheetAt(si); + assertNotNull(sh.getSheetName()); + assertEquals("Did not match for sheet " + si, topRows[si], sh.getTopRow()); + } - // for XSSF also test with SXSSF - if(isXSSF) { - Workbook swb = new SXSSFWorkbook((XSSFWorkbook) wb); - for (int si = 0; si < swb.getNumberOfSheets(); si++) { - Sheet sh = swb.getSheetAt(si); - assertNotNull(sh.getSheetName()); - assertEquals("Did not match for sheet " + si, topRows[si], sh.getLeftCol()); - } - } - } - - public void testShowInPaneManyRowsBug55248() { - XSSFWorkbook workbook = new XSSFWorkbook(); - XSSFSheet sheet = workbook.createSheet("Sheet 1"); + // for XSSF also test with SXSSF + if(isXSSF) { + Workbook swb = new SXSSFWorkbook((XSSFWorkbook) wb); + for (int si = 0; si < swb.getNumberOfSheets(); si++) { + Sheet sh = swb.getSheetAt(si); + assertNotNull(sh.getSheetName()); + assertEquals("Did not match for sheet " + si, topRows[si], sh.getTopRow()); + } + } + } + + private void runGetLeftCol(String file, boolean isXSSF, int... topRows) { + final Workbook wb; + if(isXSSF) { + wb = XSSFTestDataSamples.openSampleWorkbook(file); + } else { + wb = HSSFTestDataSamples.openSampleWorkbook(file); + } + for (int si = 0; si < wb.getNumberOfSheets(); si++) { + Sheet sh = wb.getSheetAt(si); + assertNotNull(sh.getSheetName()); + assertEquals("Did not match for sheet " + si, topRows[si], sh.getLeftCol()); + } + + // for XSSF also test with SXSSF + if(isXSSF) { + Workbook swb = new SXSSFWorkbook((XSSFWorkbook) wb); + for (int si = 0; si < swb.getNumberOfSheets(); si++) { + Sheet sh = swb.getSheetAt(si); + assertNotNull(sh.getSheetName()); + assertEquals("Did not match for sheet " + si, topRows[si], sh.getLeftCol()); + } + } + } + + @Test + public void showInPaneManyRowsBug55248() { + XSSFWorkbook workbook = new XSSFWorkbook(); + XSSFSheet sheet = workbook.createSheet("Sheet 1"); + + sheet.showInPane(0, 0); - sheet.showInPane(0, 0); - for(int i = ROW_COUNT/2;i < ROW_COUNT;i++) { sheet.createRow(i); sheet.showInPane(i, 0); // this one fails: sheet.showInPane((short)i, 0); } - - short i = 0; + + int i = 0; sheet.showInPane(i, i); - + XSSFWorkbook wb = XSSFTestDataSamples.writeOutAndReadBack(workbook); checkRowCount(wb); - } + } - public void testShowInPaneManyRowsBug55248SXSSF() { + @Test + public void showInPaneManyRowsBug55248SXSSF() { SXSSFWorkbook workbook = new SXSSFWorkbook(new XSSFWorkbook()); SXSSFSheet sheet = (SXSSFSheet) workbook.createSheet("Sheet 1"); - + sheet.showInPane(0, 0); - + for(int i = ROW_COUNT/2;i < ROW_COUNT;i++) { sheet.createRow(i); sheet.showInPane(i, 0); // this one fails: sheet.showInPane((short)i, 0); } - - short i = 0; + + int i = 0; sheet.showInPane(i, i); - + Workbook wb = SXSSFITestDataProvider.instance.writeOutAndReadBack(workbook); checkRowCount(wb); } @@ -1212,12 +1260,13 @@ public final class TestXSSFSheet extends BaseTestSheet { assertEquals(ROW_COUNT-1, sh.getLastRowNum()); } - public static void test55745() throws Exception { + @Test + public void bug55745() throws Exception { XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("55745.xlsx"); XSSFSheet sheet = wb.getSheetAt(0); List tables = sheet.getTables(); /*System.out.println(tables.size()); - + for(XSSFTable table : tables) { System.out.println("XPath: " + table.getCommonXpath()); System.out.println("Name: " + table.getName()); @@ -1230,7 +1279,8 @@ public final class TestXSSFSheet extends BaseTestSheet { assertNotNull("Sheet should contain a comments table", sheet.getCommentsTable(false)); } - public void testBug55723b(){ + @Test + public void bug55723b(){ XSSFWorkbook wb = new XSSFWorkbook(); Sheet sheet = wb.createSheet(); @@ -1240,19 +1290,25 @@ public final class TestXSSFSheet extends BaseTestSheet { CellRangeAddress range = CellRangeAddress.valueOf("A:B"); AutoFilter filter = sheet.setAutoFilter(range); assertNotNull(filter); - + // stored with a special name XSSFName name = wb.getBuiltInName(XSSFName.BUILTIN_FILTER_DB, 0); assertNotNull(name); assertEquals("Sheet0!$A:$B", name.getRefersToFormula()); - + range = CellRangeAddress.valueOf("B:C"); filter = sheet.setAutoFilter(range); assertNotNull(filter); - + // stored with a special name name = wb.getBuiltInName(XSSFName.BUILTIN_FILTER_DB, 0); assertNotNull(name); assertEquals("Sheet0!$B:$C", name.getRefersToFormula()); } -} + + @Test(timeout=180000) + public void bug51585(){ + XSSFTestDataSamples.openSampleWorkbook("51585.xlsx"); + } + +} \ No newline at end of file diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java index 9aa16d843..f47a11efd 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java @@ -17,20 +17,44 @@ package org.apache.poi.hssf.usermodel; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.List; -import junit.framework.AssertionFailedError; - import org.apache.poi.ddf.EscherDgRecord; import org.apache.poi.hssf.HSSFITestDataProvider; import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.model.DrawingManager2; import org.apache.poi.hssf.model.InternalSheet; import org.apache.poi.hssf.model.InternalWorkbook; -import org.apache.poi.hssf.record.*; +import org.apache.poi.hssf.record.AutoFilterInfoRecord; +import org.apache.poi.hssf.record.CommonObjectDataSubRecord; +import org.apache.poi.hssf.record.DimensionsRecord; +import org.apache.poi.hssf.record.FtCblsSubRecord; +import org.apache.poi.hssf.record.GridsetRecord; +import org.apache.poi.hssf.record.HCenterRecord; +import org.apache.poi.hssf.record.LbsDataSubRecord; +import org.apache.poi.hssf.record.NameRecord; +import org.apache.poi.hssf.record.ObjRecord; +import org.apache.poi.hssf.record.ObjectProtectRecord; +import org.apache.poi.hssf.record.PasswordRecord; +import org.apache.poi.hssf.record.ProtectRecord; +import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.SCLRecord; +import org.apache.poi.hssf.record.ScenarioProtectRecord; +import org.apache.poi.hssf.record.SubRecord; +import org.apache.poi.hssf.record.VCenterRecord; +import org.apache.poi.hssf.record.WSBoolRecord; +import org.apache.poi.hssf.record.WindowTwoRecord; import org.apache.poi.hssf.record.aggregates.WorksheetProtectionBlock; import org.apache.poi.hssf.usermodel.RecordInspector.RecordCollector; import org.apache.poi.ss.formula.ptg.Area3DPtg; @@ -46,6 +70,7 @@ import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddressList; import org.apache.poi.util.TempFile; +import org.junit.Test; /** * Tests HSSFSheet. This test case is very incomplete at the moment. @@ -65,7 +90,8 @@ public final class TestHSSFSheet extends BaseTestSheet { * Test for Bugzilla #29747. * Moved from TestHSSFWorkbook#testSetRepeatingRowsAndColumns(). */ - public void testSetRepeatingRowsAndColumnsBug29747() { + @Test + public void setRepeatingRowsAndColumnsBug29747() { HSSFWorkbook wb = new HSSFWorkbook(); wb.createSheet(); wb.createSheet(); @@ -76,14 +102,16 @@ public final class TestHSSFSheet extends BaseTestSheet { } - public void testTestGetSetMargin() { + @Test + public void getSetMargin() { baseTestGetSetMargin(new double[]{0.75, 0.75, 1.0, 1.0, 0.3, 0.3}); } /** * Test the gridset field gets set as expected. */ - public void testBackupRecord() { + @Test + public void backupRecord() { HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet s = wb.createSheet(); GridsetRecord gridsetRec = s.getSheet().getGridsetRecord(); @@ -96,7 +124,8 @@ public final class TestHSSFSheet extends BaseTestSheet { * Test vertically centered output. */ @SuppressWarnings("deprecation") - public void testVerticallyCenter() { + @Test + public void verticallyCenter() { HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet s = wb.createSheet(); VCenterRecord record = s.getSheet().getPageSettings().getVCenter(); @@ -115,7 +144,8 @@ public final class TestHSSFSheet extends BaseTestSheet { /** * Test horizontally centered output. */ - public void testHorizontallyCenter() { + @Test + public void horizontallyCenter() { HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet s = wb.createSheet(); HCenterRecord record = s.getSheet().getPageSettings().getHCenter(); @@ -129,7 +159,8 @@ public final class TestHSSFSheet extends BaseTestSheet { /** * Test WSBboolRecord fields get set in the user model. */ - public void testWSBool() { + @Test + public void wsBool() { HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet s = wb.createSheet(); WSBoolRecord record = @@ -177,7 +208,8 @@ public final class TestHSSFSheet extends BaseTestSheet { /** * Setting landscape and portrait stuff on existing sheets */ - public void testPrintSetupLandscapeExisting() { + @Test + public void printSetupLandscapeExisting() { HSSFWorkbook workbook = HSSFTestDataSamples.openSampleWorkbook("SimpleWithPageBreaks.xls"); assertEquals(3, workbook.getNumberOfSheets()); @@ -218,7 +250,8 @@ public final class TestHSSFSheet extends BaseTestSheet { assertEquals(1, sheetLS.getPrintSetup().getCopies()); } - public void testGroupRows() { + @Test + public void groupRows() { HSSFWorkbook workbook = new HSSFWorkbook(); HSSFSheet s = workbook.createSheet(); HSSFRow r1 = s.createRow(0); @@ -258,7 +291,8 @@ public final class TestHSSFSheet extends BaseTestSheet { assertEquals(0, r5.getOutlineLevel()); } - public void testGroupRowsExisting() { + @Test + public void groupRowsExisting() { HSSFWorkbook workbook = HSSFTestDataSamples.openSampleWorkbook("NoGutsRecords.xls"); HSSFSheet s = workbook.getSheetAt(0); @@ -290,7 +324,7 @@ public final class TestHSSFSheet extends BaseTestSheet { try { workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook); } catch (OutOfMemoryError e) { - throw new AssertionFailedError("Identified bug 39903"); + fail("Identified bug 39903"); } s = workbook.getSheetAt(0); @@ -309,7 +343,8 @@ public final class TestHSSFSheet extends BaseTestSheet { assertEquals(0, r6.getOutlineLevel()); } - public void testCreateDrawings() { + @Test + public void createDrawings() { HSSFWorkbook workbook = new HSSFWorkbook(); HSSFSheet sheet = workbook.createSheet(); HSSFPatriarch p1 = sheet.createDrawingPatriarch(); @@ -317,7 +352,8 @@ public final class TestHSSFSheet extends BaseTestSheet { assertSame(p1, p2); } - public void testGetDrawings() { + @Test + public void getDrawings() { HSSFWorkbook wb1c = HSSFTestDataSamples.openSampleWorkbook("WithChart.xls"); HSSFWorkbook wb2c = HSSFTestDataSamples.openSampleWorkbook("WithTwoCharts.xls"); @@ -341,7 +377,8 @@ public final class TestHSSFSheet extends BaseTestSheet { /** * Test that the ProtectRecord is included when creating or cloning a sheet */ - public void testCloneWithProtect() { + @Test + public void cloneWithProtect() { String passwordA = "secrect"; int expectedHashA = -6810; String passwordB = "admin"; @@ -369,7 +406,8 @@ public final class TestHSSFSheet extends BaseTestSheet { assertEquals(expectedHashA, sheet2.getSheet().getProtectionBlock().getPasswordHash()); } - public void testProtectSheetA() { + @Test + public void protectSheetA() { int expectedHash = (short)0xfef1; HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet s = wb.createSheet(); @@ -385,7 +423,8 @@ public final class TestHSSFSheet extends BaseTestSheet { * {@link PasswordRecord} belongs with the rest of the Worksheet Protection Block * (which should be before {@link DimensionsRecord}). */ - public void testProtectSheetRecordOrder_bug47363a() { + @Test + public void protectSheetRecordOrder_bug47363a() { HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet s = wb.createSheet(); s.protectSheet("secret"); @@ -394,7 +433,7 @@ public final class TestHSSFSheet extends BaseTestSheet { Record[] recs = rc.getRecords(); int nRecs = recs.length; if (recs[nRecs-2] instanceof PasswordRecord && recs[nRecs-5] instanceof DimensionsRecord) { - throw new AssertionFailedError("Identified bug 47363a - PASSWORD after DIMENSION"); + fail("Identified bug 47363a - PASSWORD after DIMENSION"); } // Check that protection block is together, and before DIMENSION confirmRecordClass(recs, nRecs-4, DimensionsRecord.class); @@ -406,8 +445,8 @@ public final class TestHSSFSheet extends BaseTestSheet { private static void confirmRecordClass(Record[] recs, int index, Class cls) { if (recs.length <= index) { - throw new AssertionFailedError("Expected (" + cls.getName() + ") at index " - + index + " but array length is " + recs.length + "."); + fail("Expected (" + cls.getName() + ") at index " + + index + " but array length is " + recs.length + "."); } assertEquals(cls, recs[index].getClass()); } @@ -415,7 +454,8 @@ public final class TestHSSFSheet extends BaseTestSheet { /** * There should be no problem with adding data validations after sheet protection */ - public void testDvProtectionOrder_bug47363b() { + @Test + public void dvProtectionOrder_bug47363b() { HSSFWorkbook workbook = new HSSFWorkbook(); HSSFSheet sheet = workbook.createSheet("Sheet1"); sheet.protectSheet("secret"); @@ -429,7 +469,7 @@ public final class TestHSSFSheet extends BaseTestSheet { } catch (IllegalStateException e) { String expMsg = "Unexpected (org.apache.poi.hssf.record.PasswordRecord) while looking for DV Table insert pos"; if (expMsg.equals(e.getMessage())) { - throw new AssertionFailedError("Identified bug 47363b"); + fail("Identified bug 47363b"); } throw e; } @@ -446,7 +486,8 @@ public final class TestHSSFSheet extends BaseTestSheet { assertEquals(4, nRecsWithProtection - nRecsWithoutProtection); } - public void testZoom() { + @Test + public void zoom() { HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet sheet = wb.createSheet(); assertEquals(-1, sheet.getSheet().findFirstRecordLocBySid(SCLRecord.sid)); @@ -490,13 +531,10 @@ public final class TestHSSFSheet extends BaseTestSheet { /** * When removing one merged region, it would break - * - */ - /** * Make sure the excel file loads work - * */ - public void testPageBreakFiles() { + @Test + public void pageBreakFiles() { HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("SimpleWithPageBreaks.xls"); HSSFSheet sheet = wb.getSheetAt(0); @@ -524,7 +562,8 @@ public final class TestHSSFSheet extends BaseTestSheet { assertEquals("column breaks number", 2, sheet.getColumnBreaks().length); } - public void testDBCSName () { + @Test + public void dbcsName () { HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("DBCSSheetName.xls"); wb.getSheetAt(1); assertEquals ("DBCS Sheet Name 2", wb.getSheetName(1),"\u090f\u0915" ); @@ -536,7 +575,8 @@ public final class TestHSSFSheet extends BaseTestSheet { * parameter to allow setting the toprow in the visible view * of the sheet when it is first opened. */ - public void testTopRow() { + @Test + public void topRow() { HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("SimpleWithPageBreaks.xls"); HSSFSheet sheet = wb.getSheetAt(0); @@ -549,10 +589,8 @@ public final class TestHSSFSheet extends BaseTestSheet { assertEquals("HSSFSheet.getLeftCol()", leftcol, sheet.getLeftCol()); } - /** - * - */ - public void testAddEmptyRow() { + @Test + public void addEmptyRow() { //try to add 5 empty rows to a new sheet HSSFWorkbook workbook = new HSSFWorkbook(); HSSFSheet sheet = workbook.createSheet(); @@ -572,7 +610,8 @@ public final class TestHSSFSheet extends BaseTestSheet { } @SuppressWarnings("deprecation") - public void testAutoSizeColumn() { + @Test + public void autoSizeColumn() { HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("43902.xls"); String sheetName = "my sheet"; HSSFSheet sheet = wb.getSheet(sheetName); @@ -614,7 +653,8 @@ public final class TestHSSFSheet extends BaseTestSheet { assertTrue(sheet3.getColumnWidth(0) <= maxWithRow1And2); } - public void testAutoSizeDate() throws Exception { + @Test + public void autoSizeDate() throws Exception { HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet s = wb.createSheet("Sheet1"); HSSFRow r = s.createRow(0); @@ -654,7 +694,8 @@ public final class TestHSSFSheet extends BaseTestSheet { /** * Setting ForceFormulaRecalculation on sheets */ - public void testForceRecalculation() throws Exception { + @Test + public void forceRecalculation() throws Exception { HSSFWorkbook workbook = HSSFTestDataSamples.openSampleWorkbook("UncalcedRecord.xls"); HSSFSheet sheet = workbook.getSheetAt(0); @@ -721,7 +762,8 @@ public final class TestHSSFSheet extends BaseTestSheet { assertTrue(wb3.getSheetAt(3).getForceFormulaRecalculation()); } - public void testColumnWidthA() { + @Test + public void columnWidthA() { //check we can correctly read column widths from a reference workbook HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("colwidth.xls"); @@ -781,7 +823,8 @@ public final class TestHSSFSheet extends BaseTestSheet { } - public void testDefaultColumnWidth() { + @Test + public void defaultColumnWidth() { HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook( "12843-1.xls" ); HSSFSheet sheet = wb.getSheetAt( 7 ); // shall not be NPE @@ -807,16 +850,17 @@ public final class TestHSSFSheet extends BaseTestSheet { * Excel, ooo, and google docs are OK with this. * Now POI is too. */ - public void testMissingRowRecords_bug41187() { + @Test + public void missingRowRecords_bug41187() { HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("ex41187-19267.xls"); HSSFSheet sheet = wb.getSheetAt(0); HSSFRow row = sheet.getRow(0); if(row == null) { - throw new AssertionFailedError("Identified bug 41187 a"); + fail("Identified bug 41187 a"); } if (row.getHeight() == 0) { - throw new AssertionFailedError("Identified bug 41187 b"); + fail("Identified bug 41187 b"); } assertEquals("Hi Excel!", row.getCell(0).getRichStringCellValue().getString()); // check row height for 'default' flag @@ -831,7 +875,8 @@ public final class TestHSSFSheet extends BaseTestSheet { * * See bug #45720. */ - public void testCloneSheetWithDrawings() { + @Test + public void cloneSheetWithDrawings() { HSSFWorkbook wb1 = HSSFTestDataSamples.openSampleWorkbook("45720.xls"); HSSFSheet sheet1 = wb1.getSheetAt(0); @@ -865,14 +910,15 @@ public final class TestHSSFSheet extends BaseTestSheet { * Since Excel silently truncates to 31, make sure that POI enforces uniqueness on the first * 31 chars. */ - public void testLongSheetNames() { + @Test + public void longSheetNames() { HSSFWorkbook wb = new HSSFWorkbook(); final String SAME_PREFIX = "A123456789B123456789C123456789"; // 30 chars wb.createSheet(SAME_PREFIX + "Dxxxx"); try { wb.createSheet(SAME_PREFIX + "Dyyyy"); // identical up to the 32nd char - throw new AssertionFailedError("Expected exception not thrown"); + fail("Expected exception not thrown"); } catch (IllegalArgumentException e) { assertEquals("The workbook already contains a sheet of this name", e.getMessage()); } @@ -882,7 +928,8 @@ public final class TestHSSFSheet extends BaseTestSheet { /** * Tests that we can read existing column styles */ - public void testReadColumnStyles() { + @Test + public void readColumnStyles() { HSSFWorkbook wbNone = HSSFTestDataSamples.openSampleWorkbook("ColumnStyleNone.xls"); HSSFWorkbook wbSimple = HSSFTestDataSamples.openSampleWorkbook("ColumnStyle1dp.xls"); HSSFWorkbook wbComplex = HSSFTestDataSamples.openSampleWorkbook("ColumnStyle1dpColoured.xls"); @@ -921,7 +968,8 @@ public final class TestHSSFSheet extends BaseTestSheet { /** * Tests the arabic setting */ - public void testArabic() { + @Test + public void arabic() { HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet s = wb.createSheet(); @@ -930,7 +978,8 @@ public final class TestHSSFSheet extends BaseTestSheet { assertTrue(s.isRightToLeft()); } - public void testAutoFilter(){ + @Test + public void autoFilter(){ HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet sh = wb.createSheet(); InternalWorkbook iwb = wb.getWorkbook(); @@ -979,14 +1028,16 @@ public final class TestHSSFSheet extends BaseTestSheet { assertTrue(subRecords.get(2) instanceof LbsDataSubRecord ); } - public void testGetSetColumnHiddenShort() { + @Test + public void getSetColumnHiddenShort() { Workbook workbook = new HSSFWorkbook(); Sheet sheet = workbook.createSheet("Sheet 1"); sheet.setColumnHidden((short)2, true); assertTrue(sheet.isColumnHidden((short)2)); } - public void testColumnWidthShort() { + @Test + public void columnWidthShort() { HSSFWorkbook wb = new HSSFWorkbook(); Sheet sheet = wb.createSheet(); @@ -1045,20 +1096,19 @@ public final class TestHSSFSheet extends BaseTestSheet { assertEquals(40000, sheet.getColumnWidth((short)10)); } - public void testShowInPane() { + @Test + public void showInPane() { Workbook wb = new HSSFWorkbook(); Sheet sheet = wb.createSheet(); sheet.showInPane(2, 3); - try { - sheet.showInPane(Integer.MAX_VALUE, 3); - fail("Should catch exception here"); - } catch (IllegalArgumentException e) { - assertEquals("Maximum row number is 65535", e.getMessage()); - } + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("Maximum row number is 65535"); + sheet.showInPane(Integer.MAX_VALUE, 3); } - public void testDrawingRecords() { + @Test + public void drawingRecords() { HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet sheet = wb.createSheet(); @@ -1068,7 +1118,8 @@ public final class TestHSSFSheet extends BaseTestSheet { assertNull(sheet.getDrawingEscherAggregate()); } - public void testBug55723b() { + @Test + public void bug55723b() { HSSFWorkbook wb = new HSSFWorkbook(); Sheet sheet = wb.createSheet(); diff --git a/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheet.java b/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheet.java index 370b1c121..480235f5e 100644 --- a/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheet.java +++ b/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheet.java @@ -17,29 +17,41 @@ package org.apache.poi.ss.usermodel; -import java.util.Iterator; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; -import junit.framework.TestCase; +import java.util.Iterator; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.util.PaneInformation; import org.apache.poi.ss.ITestDataProvider; import org.apache.poi.ss.SpreadsheetVersion; import org.apache.poi.ss.util.CellRangeAddress; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; /** * Common superclass for testing {@link org.apache.poi.xssf.usermodel.XSSFCell} and * {@link org.apache.poi.hssf.usermodel.HSSFCell} */ -public abstract class BaseTestSheet extends TestCase { - +public abstract class BaseTestSheet { + @Rule + public ExpectedException thrown = ExpectedException.none(); + private final ITestDataProvider _testDataProvider; protected BaseTestSheet(ITestDataProvider testDataProvider) { _testDataProvider = testDataProvider; } - public void testCreateRow() { + @Test + public void createRow() { Workbook workbook = _testDataProvider.createWorkbook(); Sheet sheet = workbook.createSheet(); assertEquals(0, sheet.getPhysicalNumberOfRows()); @@ -79,7 +91,8 @@ public abstract class BaseTestSheet extends TestCase { } - public void testRemoveRow() { + @Test + public void removeRow() { Workbook workbook = _testDataProvider.createWorkbook(); Sheet sheet1 = workbook.createSheet(); assertEquals(0, sheet1.getPhysicalNumberOfRows()); @@ -112,15 +125,14 @@ public abstract class BaseTestSheet extends TestCase { Row row3 = sheet1.createRow(3); Sheet sheet2 = workbook.createSheet(); - try { - sheet2.removeRow(row3); - fail("Expected exception"); - } catch (IllegalArgumentException e){ - assertEquals("Specified row does not belong to this sheet", e.getMessage()); - } + + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("Specified row does not belong to this sheet"); + sheet2.removeRow(row3); } - public void testCloneSheet() { + @Test + public void cloneSheet() { Workbook workbook = _testDataProvider.createWorkbook(); CreationHelper factory = workbook.getCreationHelper(); Sheet sheet = workbook.createSheet("Test Clone"); @@ -152,7 +164,8 @@ public abstract class BaseTestSheet extends TestCase { /** tests that the sheet name for multiple clones of the same sheet is unique * BUG 37416 */ - public void testCloneSheetMultipleTimes() { + @Test + public void cloneSheetMultipleTimes() { Workbook workbook = _testDataProvider.createWorkbook(); CreationHelper factory = workbook.getCreationHelper(); Sheet sheet = workbook.createSheet("Test Clone"); @@ -179,7 +192,8 @@ public abstract class BaseTestSheet extends TestCase { /** * Setting landscape and portrait stuff on new sheets */ - public void testPrintSetupLandscapeNew() { + @Test + public void printSetupLandscapeNew() { Workbook workbook = _testDataProvider.createWorkbook(); Sheet sheetL = workbook.createSheet("LandscapeS"); Sheet sheetP = workbook.createSheet("LandscapeP"); @@ -216,7 +230,8 @@ public abstract class BaseTestSheet extends TestCase { * then an IllegalArgumentException should be thrown * */ - public void testAddMerged() { + @Test + public void addMerged() { Workbook wb = _testDataProvider.createWorkbook(); Sheet sheet = wb.createSheet(); assertEquals(0, sheet.getNumMergedRegions()); @@ -231,7 +246,7 @@ public abstract class BaseTestSheet extends TestCase { sheet.addMergedRegion(region); fail("Expected exception"); } catch (IllegalArgumentException e){ -// TODO assertEquals("Minimum row number is 0.", e.getMessage()); + // TODO: assertEquals("Minimum row number is 0.", e.getMessage()); } try { region = new CellRangeAddress(0, 0, 0, ssVersion.getLastColumnIndex() + 1); @@ -254,7 +269,8 @@ public abstract class BaseTestSheet extends TestCase { * When removing one merged region, it would break * */ - public void testRemoveMerged() { + @Test + public void removeMerged() { Workbook wb = _testDataProvider.createWorkbook(); Sheet sheet = wb.createSheet(); CellRangeAddress region = new CellRangeAddress(0, 1, 0, 1); @@ -288,7 +304,8 @@ public abstract class BaseTestSheet extends TestCase { assertEquals("the merged row to doesnt match the one we put in ", 4, region.getLastRow()); } - public void testShiftMerged() { + @Test + public void shiftMerged() { Workbook wb = _testDataProvider.createWorkbook(); CreationHelper factory = wb.getCreationHelper(); Sheet sheet = wb.createSheet(); @@ -313,7 +330,8 @@ public abstract class BaseTestSheet extends TestCase { * Tests the display of gridlines, formulas, and rowcolheadings. * @author Shawn Laubach (slaubach at apache dot org) */ - public void testDisplayOptions() { + @Test + public void displayOptions() { Workbook wb = _testDataProvider.createWorkbook(); Sheet sheet = wb.createSheet(); @@ -336,7 +354,8 @@ public abstract class BaseTestSheet extends TestCase { assertEquals(sheet.isDisplayZeros(), false); } - public void testColumnWidth() { + @Test + public void columnWidth() { Workbook wb = _testDataProvider.createWorkbook(); Sheet sheet = wb.createSheet(); @@ -396,7 +415,8 @@ public abstract class BaseTestSheet extends TestCase { } - public void testDefaultRowHeight() { + @Test + public void defaultRowHeight() { Workbook workbook = _testDataProvider.createWorkbook(); Sheet sheet = workbook.createSheet(); sheet.setDefaultRowHeightInPoints(15); @@ -424,7 +444,8 @@ public abstract class BaseTestSheet extends TestCase { } /** cell with formula becomes null on cloning a sheet*/ - public void test35084() { + @Test + public void bug35084() { Workbook wb = _testDataProvider.createWorkbook(); Sheet s = wb.createSheet("Sheet1"); Row r = s.createRow(0); @@ -438,7 +459,8 @@ public abstract class BaseTestSheet extends TestCase { } /** test that new default column styles get applied */ - public void testDefaultColumnStyle() { + @Test + public void defaultColumnStyle() { Workbook wb = _testDataProvider.createWorkbook(); CellStyle style = wb.createCellStyle(); Sheet sheet = wb.createSheet(); @@ -453,7 +475,8 @@ public abstract class BaseTestSheet extends TestCase { assertEquals("style should match", style.getIndex(), style2.getIndex()); } - public void testOutlineProperties() { + @Test + public void outlineProperties() { Workbook wb = _testDataProvider.createWorkbook(); Sheet sheet = wb.createSheet(); @@ -483,7 +506,8 @@ public abstract class BaseTestSheet extends TestCase { /** * Test basic display properties */ - public void testSheetProperties() { + @Test + public void sheetProperties() { Workbook wb = _testDataProvider.createWorkbook(); Sheet sheet = wb.createSheet(); @@ -565,15 +589,13 @@ public abstract class BaseTestSheet extends TestCase { assertEquals(11.5, sheet.getMargin(Sheet.HeaderMargin), 0.0); // incorrect margin constant - try { - sheet.setMargin((short) 65, 15); - fail("Expected exception"); - } catch (IllegalArgumentException e){ - assertEquals("Unknown margin constant: 65", e.getMessage()); - } + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("Unknown margin constant: 65"); + sheet.setMargin((short) 65, 15); } - public void testRowBreaks() { + @Test + public void rowBreaks() { Workbook workbook = _testDataProvider.createWorkbook(); Sheet sheet = workbook.createSheet(); //Sheet#getRowBreaks() returns an empty array if no row breaks are defined @@ -601,7 +623,8 @@ public abstract class BaseTestSheet extends TestCase { assertFalse(sheet.isRowBroken(15)); } - public void testColumnBreaks() { + @Test + public void columnBreaks() { Workbook workbook = _testDataProvider.createWorkbook(); Sheet sheet = workbook.createSheet(); assertNotNull(sheet.getColumnBreaks()); @@ -628,7 +651,8 @@ public abstract class BaseTestSheet extends TestCase { assertFalse(sheet.isColumnBroken(12)); } - public void testGetFirstLastRowNum() { + @Test + public void getFirstLastRowNum() { Workbook workbook = _testDataProvider.createWorkbook(); Sheet sheet = workbook.createSheet("Sheet 1"); sheet.createRow(9); @@ -638,7 +662,8 @@ public abstract class BaseTestSheet extends TestCase { assertEquals(9, sheet.getLastRowNum()); } - public void testGetFooter() { + @Test + public void getFooter() { Workbook workbook = _testDataProvider.createWorkbook(); Sheet sheet = workbook.createSheet("Sheet 1"); assertNotNull(sheet.getFooter()); @@ -646,26 +671,28 @@ public abstract class BaseTestSheet extends TestCase { assertEquals("test center footer", sheet.getFooter().getCenter()); } - public void testGetSetColumnHidden() { + @Test + public void getSetColumnHidden() { Workbook workbook = _testDataProvider.createWorkbook(); Sheet sheet = workbook.createSheet("Sheet 1"); sheet.setColumnHidden(2, true); assertTrue(sheet.isColumnHidden(2)); } - public void testProtectSheet() { - - Workbook wb = _testDataProvider.createWorkbook(); - Sheet sheet = wb.createSheet(); + @Test + public void protectSheet() { + Workbook wb = _testDataProvider.createWorkbook(); + Sheet sheet = wb.createSheet(); + assertFalse(sheet.getProtect()); + sheet.protectSheet("Test"); + assertTrue(sheet.getProtect()); + sheet.protectSheet(null); assertFalse(sheet.getProtect()); - sheet.protectSheet("Test"); - assertTrue(sheet.getProtect()); - sheet.protectSheet(null); - assertFalse(sheet.getProtect()); } - public void testCreateFreezePane() { + @Test + public void createFreezePane() { Workbook wb = _testDataProvider.createWorkbook(); // create a workbook Sheet sheet = wb.createSheet(); @@ -715,7 +742,8 @@ public abstract class BaseTestSheet extends TestCase { } - public void testGetRepeatingRowsAndColumns() { + @Test + public void getRepeatingRowsAndColumns() { Workbook wb = _testDataProvider.openSampleWorkbook( "RepeatingRowsCols." + _testDataProvider.getStandardFileNameExtension()); @@ -727,7 +755,8 @@ public abstract class BaseTestSheet extends TestCase { } - public void testSetRepeatingRowsAndColumnsBug47294(){ + @Test + public void setRepeatingRowsAndColumnsBug47294(){ Workbook wb = _testDataProvider.createWorkbook(); Sheet sheet1 = wb.createSheet(); sheet1.setRepeatingRows(CellRangeAddress.valueOf("1:4")); @@ -739,56 +768,58 @@ public abstract class BaseTestSheet extends TestCase { assertEquals("1:4", sheet2.getRepeatingRows().formatAsString()); } - public void testSetRepeatingRowsAndColumns() { - Workbook wb = _testDataProvider.createWorkbook(); - Sheet sheet1 = wb.createSheet("Sheet1"); - Sheet sheet2 = wb.createSheet("Sheet2"); - Sheet sheet3 = wb.createSheet("Sheet3"); - - checkRepeatingRowsAndColumns(sheet1, null, null); - - sheet1.setRepeatingRows(CellRangeAddress.valueOf("4:5")); - sheet2.setRepeatingColumns(CellRangeAddress.valueOf("A:C")); - sheet3.setRepeatingRows(CellRangeAddress.valueOf("1:4")); - sheet3.setRepeatingColumns(CellRangeAddress.valueOf("A:A")); - - checkRepeatingRowsAndColumns(sheet1, "4:5", null); - checkRepeatingRowsAndColumns(sheet2, null, "A:C"); - checkRepeatingRowsAndColumns(sheet3, "1:4", "A:A"); - - // write out, read back, and test refrain... - wb = _testDataProvider.writeOutAndReadBack(wb); - sheet1 = wb.getSheetAt(0); - sheet2 = wb.getSheetAt(1); - sheet3 = wb.getSheetAt(2); - - checkRepeatingRowsAndColumns(sheet1, "4:5", null); - checkRepeatingRowsAndColumns(sheet2, null, "A:C"); - checkRepeatingRowsAndColumns(sheet3, "1:4", "A:A"); - - // check removing repeating rows and columns - sheet3.setRepeatingRows(null); - checkRepeatingRowsAndColumns(sheet3, null, "A:A"); - - sheet3.setRepeatingColumns(null); - checkRepeatingRowsAndColumns(sheet3, null, null); + @Test + public void setRepeatingRowsAndColumns() { + Workbook wb = _testDataProvider.createWorkbook(); + Sheet sheet1 = wb.createSheet("Sheet1"); + Sheet sheet2 = wb.createSheet("Sheet2"); + Sheet sheet3 = wb.createSheet("Sheet3"); + + checkRepeatingRowsAndColumns(sheet1, null, null); + + sheet1.setRepeatingRows(CellRangeAddress.valueOf("4:5")); + sheet2.setRepeatingColumns(CellRangeAddress.valueOf("A:C")); + sheet3.setRepeatingRows(CellRangeAddress.valueOf("1:4")); + sheet3.setRepeatingColumns(CellRangeAddress.valueOf("A:A")); + + checkRepeatingRowsAndColumns(sheet1, "4:5", null); + checkRepeatingRowsAndColumns(sheet2, null, "A:C"); + checkRepeatingRowsAndColumns(sheet3, "1:4", "A:A"); + + // write out, read back, and test refrain... + wb = _testDataProvider.writeOutAndReadBack(wb); + sheet1 = wb.getSheetAt(0); + sheet2 = wb.getSheetAt(1); + sheet3 = wb.getSheetAt(2); + + checkRepeatingRowsAndColumns(sheet1, "4:5", null); + checkRepeatingRowsAndColumns(sheet2, null, "A:C"); + checkRepeatingRowsAndColumns(sheet3, "1:4", "A:A"); + + // check removing repeating rows and columns + sheet3.setRepeatingRows(null); + checkRepeatingRowsAndColumns(sheet3, null, "A:A"); + + sheet3.setRepeatingColumns(null); + checkRepeatingRowsAndColumns(sheet3, null, null); } private void checkRepeatingRowsAndColumns( Sheet s, String expectedRows, String expectedCols) { - if (expectedRows == null) { - assertNull(s.getRepeatingRows()); - } else { - assertEquals(expectedRows, s.getRepeatingRows().formatAsString()); - } - if (expectedCols == null) { - assertNull(s.getRepeatingColumns()); - } else { - assertEquals(expectedCols, s.getRepeatingColumns().formatAsString()); - } + if (expectedRows == null) { + assertNull(s.getRepeatingRows()); + } else { + assertEquals(expectedRows, s.getRepeatingRows().formatAsString()); + } + if (expectedCols == null) { + assertNull(s.getRepeatingColumns()); + } else { + assertEquals(expectedCols, s.getRepeatingColumns().formatAsString()); + } } - public void testBaseZoom() { + @Test + public void baseZoom() { Workbook wb = _testDataProvider.createWorkbook(); Sheet sheet = wb.createSheet(); @@ -796,14 +827,15 @@ public abstract class BaseTestSheet extends TestCase { sheet.setZoom(3,4); } - public void testBaseShowInPane() { + @Test + public void baseShowInPane() { Workbook wb = _testDataProvider.createWorkbook(); Sheet sheet = wb.createSheet(); sheet.showInPane(2, 3); } - - public void testBug55723(){ + @Test + public void bug55723(){ Workbook wb = _testDataProvider.createWorkbook(); Sheet sheet = wb.createSheet(); @@ -818,7 +850,8 @@ public abstract class BaseTestSheet extends TestCase { // there seems to be currently no generic way to check the setting... } - public void testBug55723_Rows() { + @Test + public void bug55723_Rows() { HSSFWorkbook wb = new HSSFWorkbook(); Sheet sheet = wb.createSheet(); @@ -827,8 +860,8 @@ public abstract class BaseTestSheet extends TestCase { assertNotNull(filter); } - - public void testBug55723d_RowsOver65k() { + @Test + public void bug55723d_RowsOver65k() { HSSFWorkbook wb = new HSSFWorkbook(); Sheet sheet = wb.createSheet(); diff --git a/test-data/spreadsheet/51585.xlsx b/test-data/spreadsheet/51585.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..479c8dbdcd1d0e7854baa7077bde960d2ffcb823 GIT binary patch literal 262225 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 LUr~o?X!HL7pU6=# literal 0 HcmV?d00001 From 6f6c6cda3445f8c3178ca4988bada82bd09e8c19 Mon Sep 17 00:00:00 2001 From: Andreas Beeker Date: Sun, 26 Jan 2014 15:01:12 +0000 Subject: [PATCH 09/11] As Jdk 1.5 doesn't provide NavigableMap/Set classes of JDK 1.6, we temporarily use the open jdk classes instead, until POI has switched to JDK 1.6 git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1561500 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/util/java7_util/AbstractMap7.java | 828 ++++++ .../poi/util/java7_util/AbstractSet7.java | 190 ++ .../poi/util/java7_util/NavigableMap7.java | 429 +++ .../poi/util/java7_util/NavigableSet7.java | 324 +++ .../apache/poi/util/java7_util/TreeMap7.java | 2458 +++++++++++++++++ .../apache/poi/util/java7_util/TreeSet7.java | 554 ++++ .../xssf/usermodel/helpers/ColumnHelper.java | 4 +- 7 files changed, 4785 insertions(+), 2 deletions(-) create mode 100644 src/ooxml/java/org/apache/poi/util/java7_util/AbstractMap7.java create mode 100644 src/ooxml/java/org/apache/poi/util/java7_util/AbstractSet7.java create mode 100644 src/ooxml/java/org/apache/poi/util/java7_util/NavigableMap7.java create mode 100644 src/ooxml/java/org/apache/poi/util/java7_util/NavigableSet7.java create mode 100644 src/ooxml/java/org/apache/poi/util/java7_util/TreeMap7.java create mode 100644 src/ooxml/java/org/apache/poi/util/java7_util/TreeSet7.java diff --git a/src/ooxml/java/org/apache/poi/util/java7_util/AbstractMap7.java b/src/ooxml/java/org/apache/poi/util/java7_util/AbstractMap7.java new file mode 100644 index 000000000..6e65da7f2 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/util/java7_util/AbstractMap7.java @@ -0,0 +1,828 @@ +/* + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.apache.poi.util.java7_util; + +import java.util.AbstractCollection; +import java.util.AbstractSet; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * This class provides a skeletal implementation of the Map + * interface, to minimize the effort required to implement this interface. + * + *

To implement an unmodifiable map, the programmer needs only to extend this + * class and provide an implementation for the entrySet method, which + * returns a set-view of the map's mappings. Typically, the returned set + * will, in turn, be implemented atop AbstractSet. This set should + * not support the add or remove methods, and its iterator + * should not support the remove method. + * + *

To implement a modifiable map, the programmer must additionally override + * this class's put method (which otherwise throws an + * UnsupportedOperationException), and the iterator returned by + * entrySet().iterator() must additionally implement its + * remove method. + * + *

The programmer should generally provide a void (no argument) and map + * constructor, as per the recommendation in the Map interface + * specification. + * + *

The documentation for each non-abstract method in this class describes its + * implementation in detail. Each of these methods may be overridden if the + * map being implemented admits a more efficient implementation. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @param the type of keys maintained by this map + * @param the type of mapped values + * + * @author Josh Bloch + * @author Neal Gafter + * @see Map + * @see Collection + * @since 1.2 + */ + +public abstract class AbstractMap7 implements Map { + /** + * Sole constructor. (For invocation by subclass constructors, typically + * implicit.) + */ + protected AbstractMap7() { + } + + // Query Operations + + /** + * {@inheritDoc} + * + *

This implementation returns entrySet().size(). + */ + public int size() { + return entrySet().size(); + } + + /** + * {@inheritDoc} + * + *

This implementation returns size() == 0. + */ + public boolean isEmpty() { + return size() == 0; + } + + /** + * {@inheritDoc} + * + *

This implementation iterates over entrySet() searching + * for an entry with the specified value. If such an entry is found, + * true is returned. If the iteration terminates without + * finding such an entry, false is returned. Note that this + * implementation requires linear time in the size of the map. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public boolean containsValue(Object value) { + Iterator> i = entrySet().iterator(); + if (value==null) { + while (i.hasNext()) { + Entry e = i.next(); + if (e.getValue()==null) + return true; + } + } else { + while (i.hasNext()) { + Entry e = i.next(); + if (value.equals(e.getValue())) + return true; + } + } + return false; + } + + /** + * {@inheritDoc} + * + *

This implementation iterates over entrySet() searching + * for an entry with the specified key. If such an entry is found, + * true is returned. If the iteration terminates without + * finding such an entry, false is returned. Note that this + * implementation requires linear time in the size of the map; many + * implementations will override this method. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public boolean containsKey(Object key) { + Iterator> i = entrySet().iterator(); + if (key==null) { + while (i.hasNext()) { + Entry e = i.next(); + if (e.getKey()==null) + return true; + } + } else { + while (i.hasNext()) { + Entry e = i.next(); + if (key.equals(e.getKey())) + return true; + } + } + return false; + } + + /** + * {@inheritDoc} + * + *

This implementation iterates over entrySet() searching + * for an entry with the specified key. If such an entry is found, + * the entry's value is returned. If the iteration terminates without + * finding such an entry, null is returned. Note that this + * implementation requires linear time in the size of the map; many + * implementations will override this method. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public V get(Object key) { + Iterator> i = entrySet().iterator(); + if (key==null) { + while (i.hasNext()) { + Entry e = i.next(); + if (e.getKey()==null) + return e.getValue(); + } + } else { + while (i.hasNext()) { + Entry e = i.next(); + if (key.equals(e.getKey())) + return e.getValue(); + } + } + return null; + } + + + // Modification Operations + + /** + * {@inheritDoc} + * + *

This implementation always throws an + * UnsupportedOperationException. + * + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public V put(K key, V value) { + throw new UnsupportedOperationException(); + } + + /** + * {@inheritDoc} + * + *

This implementation iterates over entrySet() searching for an + * entry with the specified key. If such an entry is found, its value is + * obtained with its getValue operation, the entry is removed + * from the collection (and the backing map) with the iterator's + * remove operation, and the saved value is returned. If the + * iteration terminates without finding such an entry, null is + * returned. Note that this implementation requires linear time in the + * size of the map; many implementations will override this method. + * + *

Note that this implementation throws an + * UnsupportedOperationException if the entrySet + * iterator does not support the remove method and this map + * contains a mapping for the specified key. + * + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public V remove(Object key) { + Iterator> i = entrySet().iterator(); + Entry correctEntry = null; + if (key==null) { + while (correctEntry==null && i.hasNext()) { + Entry e = i.next(); + if (e.getKey()==null) + correctEntry = e; + } + } else { + while (correctEntry==null && i.hasNext()) { + Entry e = i.next(); + if (key.equals(e.getKey())) + correctEntry = e; + } + } + + V oldValue = null; + if (correctEntry !=null) { + oldValue = correctEntry.getValue(); + i.remove(); + } + return oldValue; + } + + + // Bulk Operations + + /** + * {@inheritDoc} + * + *

This implementation iterates over the specified map's + * entrySet() collection, and calls this map's put + * operation once for each entry returned by the iteration. + * + *

Note that this implementation throws an + * UnsupportedOperationException if this map does not support + * the put operation and the specified map is nonempty. + * + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public void putAll(Map m) { + for (Map.Entry e : m.entrySet()) + put(e.getKey(), e.getValue()); + } + + /** + * {@inheritDoc} + * + *

This implementation calls entrySet().clear(). + * + *

Note that this implementation throws an + * UnsupportedOperationException if the entrySet + * does not support the clear operation. + * + * @throws UnsupportedOperationException {@inheritDoc} + */ + public void clear() { + entrySet().clear(); + } + + + // Views + + /** + * Each of these fields are initialized to contain an instance of the + * appropriate view the first time this view is requested. The views are + * stateless, so there's no reason to create more than one of each. + */ + transient volatile Set keySet = null; + transient volatile Collection values = null; + + /** + * {@inheritDoc} + * + *

This implementation returns a set that subclasses {@link AbstractSet}. + * The subclass's iterator method returns a "wrapper object" over this + * map's entrySet() iterator. The size method + * delegates to this map's size method and the + * contains method delegates to this map's + * containsKey method. + * + *

The set is created the first time this method is called, + * and returned in response to all subsequent calls. No synchronization + * is performed, so there is a slight chance that multiple calls to this + * method will not all return the same set. + */ + public Set keySet() { + if (keySet == null) { + keySet = new AbstractSet() { + public Iterator iterator() { + return new Iterator() { + private Iterator> i = entrySet().iterator(); + + public boolean hasNext() { + return i.hasNext(); + } + + public K next() { + return i.next().getKey(); + } + + public void remove() { + i.remove(); + } + }; + } + + public int size() { + return AbstractMap7.this.size(); + } + + public boolean isEmpty() { + return AbstractMap7.this.isEmpty(); + } + + public void clear() { + AbstractMap7.this.clear(); + } + + public boolean contains(Object k) { + return AbstractMap7.this.containsKey(k); + } + }; + } + return keySet; + } + + /** + * {@inheritDoc} + * + *

This implementation returns a collection that subclasses {@link + * AbstractCollection}. The subclass's iterator method returns a + * "wrapper object" over this map's entrySet() iterator. + * The size method delegates to this map's size + * method and the contains method delegates to this map's + * containsValue method. + * + *

The collection is created the first time this method is called, and + * returned in response to all subsequent calls. No synchronization is + * performed, so there is a slight chance that multiple calls to this + * method will not all return the same collection. + */ + public Collection values() { + if (values == null) { + values = new AbstractCollection() { + public Iterator iterator() { + return new Iterator() { + private Iterator> i = entrySet().iterator(); + + public boolean hasNext() { + return i.hasNext(); + } + + public V next() { + return i.next().getValue(); + } + + public void remove() { + i.remove(); + } + }; + } + + public int size() { + return AbstractMap7.this.size(); + } + + public boolean isEmpty() { + return AbstractMap7.this.isEmpty(); + } + + public void clear() { + AbstractMap7.this.clear(); + } + + public boolean contains(Object v) { + return AbstractMap7.this.containsValue(v); + } + }; + } + return values; + } + + public abstract Set> entrySet(); + + + // Comparison and hashing + + /** + * Compares the specified object with this map for equality. Returns + * true if the given object is also a map and the two maps + * represent the same mappings. More formally, two maps m1 and + * m2 represent the same mappings if + * m1.entrySet().equals(m2.entrySet()). This ensures that the + * equals method works properly across different implementations + * of the Map interface. + * + *

This implementation first checks if the specified object is this map; + * if so it returns true. Then, it checks if the specified + * object is a map whose size is identical to the size of this map; if + * not, it returns false. If so, it iterates over this map's + * entrySet collection, and checks that the specified map + * contains each mapping that this map contains. If the specified map + * fails to contain such a mapping, false is returned. If the + * iteration completes, true is returned. + * + * @param o object to be compared for equality with this map + * @return true if the specified object is equal to this map + */ + public boolean equals(Object o) { + if (o == this) + return true; + + if (!(o instanceof Map)) + return false; + Map m = (Map) o; + if (m.size() != size()) + return false; + + try { + Iterator> i = entrySet().iterator(); + while (i.hasNext()) { + Entry e = i.next(); + K key = e.getKey(); + V value = e.getValue(); + if (value == null) { + if (!(m.get(key)==null && m.containsKey(key))) + return false; + } else { + if (!value.equals(m.get(key))) + return false; + } + } + } catch (ClassCastException unused) { + return false; + } catch (NullPointerException unused) { + return false; + } + + return true; + } + + /** + * Returns the hash code value for this map. The hash code of a map is + * defined to be the sum of the hash codes of each entry in the map's + * entrySet() view. This ensures that m1.equals(m2) + * implies that m1.hashCode()==m2.hashCode() for any two maps + * m1 and m2, as required by the general contract of + * {@link Object#hashCode}. + * + *

This implementation iterates over entrySet(), calling + * {@link Map.Entry#hashCode hashCode()} on each element (entry) in the + * set, and adding up the results. + * + * @return the hash code value for this map + * @see Map.Entry#hashCode() + * @see Object#equals(Object) + * @see Set#equals(Object) + */ + public int hashCode() { + int h = 0; + Iterator> i = entrySet().iterator(); + while (i.hasNext()) + h += i.next().hashCode(); + return h; + } + + /** + * Returns a string representation of this map. The string representation + * consists of a list of key-value mappings in the order returned by the + * map's entrySet view's iterator, enclosed in braces + * ("{}"). Adjacent mappings are separated by the characters + * ", " (comma and space). Each key-value mapping is rendered as + * the key followed by an equals sign ("=") followed by the + * associated value. Keys and values are converted to strings as by + * {@link String#valueOf(Object)}. + * + * @return a string representation of this map + */ + public String toString() { + Iterator> i = entrySet().iterator(); + if (! i.hasNext()) + return "{}"; + + StringBuilder sb = new StringBuilder(); + sb.append('{'); + for (;;) { + Entry e = i.next(); + K key = e.getKey(); + V value = e.getValue(); + sb.append(key == this ? "(this Map)" : key); + sb.append('='); + sb.append(value == this ? "(this Map)" : value); + if (! i.hasNext()) + return sb.append('}').toString(); + sb.append(',').append(' '); + } + } + + /** + * Returns a shallow copy of this AbstractMap7 instance: the keys + * and values themselves are not cloned. + * + * @return a shallow copy of this map + */ + protected Object clone() throws CloneNotSupportedException { + AbstractMap7 result = (AbstractMap7)super.clone(); + result.keySet = null; + result.values = null; + return result; + } + + /** + * Utility method for SimpleEntry and SimpleImmutableEntry. + * Test for equality, checking for nulls. + */ + private static boolean eq(Object o1, Object o2) { + return o1 == null ? o2 == null : o1.equals(o2); + } + + // Implementation Note: SimpleEntry and SimpleImmutableEntry + // are distinct unrelated classes, even though they share + // some code. Since you can't add or subtract final-ness + // of a field in a subclass, they can't share representations, + // and the amount of duplicated code is too small to warrant + // exposing a common abstract class. + + + /** + * An Entry maintaining a key and a value. The value may be + * changed using the setValue method. This class + * facilitates the process of building custom map + * implementations. For example, it may be convenient to return + * arrays of SimpleEntry instances in method + * Map.entrySet().toArray. + * + * @since 1.6 + */ + public static class SimpleEntry + implements Entry, java.io.Serializable + { + private static final long serialVersionUID = -8499721149061103585L; + + private final K key; + private V value; + + /** + * Creates an entry representing a mapping from the specified + * key to the specified value. + * + * @param key the key represented by this entry + * @param value the value represented by this entry + */ + public SimpleEntry(K key, V value) { + this.key = key; + this.value = value; + } + + /** + * Creates an entry representing the same mapping as the + * specified entry. + * + * @param entry the entry to copy + */ + public SimpleEntry(Entry entry) { + this.key = entry.getKey(); + this.value = entry.getValue(); + } + + /** + * Returns the key corresponding to this entry. + * + * @return the key corresponding to this entry + */ + public K getKey() { + return key; + } + + /** + * Returns the value corresponding to this entry. + * + * @return the value corresponding to this entry + */ + public V getValue() { + return value; + } + + /** + * Replaces the value corresponding to this entry with the specified + * value. + * + * @param value new value to be stored in this entry + * @return the old value corresponding to the entry + */ + public V setValue(V value) { + V oldValue = this.value; + this.value = value; + return oldValue; + } + + /** + * Compares the specified object with this entry for equality. + * Returns {@code true} if the given object is also a map entry and + * the two entries represent the same mapping. More formally, two + * entries {@code e1} and {@code e2} represent the same mapping + * if

+         *   (e1.getKey()==null ?
+         *    e2.getKey()==null :
+         *    e1.getKey().equals(e2.getKey()))
+         *   &&
+         *   (e1.getValue()==null ?
+         *    e2.getValue()==null :
+         *    e1.getValue().equals(e2.getValue()))
+ * This ensures that the {@code equals} method works properly across + * different implementations of the {@code Map.Entry} interface. + * + * @param o object to be compared for equality with this map entry + * @return {@code true} if the specified object is equal to this map + * entry + * @see #hashCode + */ + public boolean equals(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry e = (Map.Entry)o; + return eq(key, e.getKey()) && eq(value, e.getValue()); + } + + /** + * Returns the hash code value for this map entry. The hash code + * of a map entry {@code e} is defined to be:
+         *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
+         *   (e.getValue()==null ? 0 : e.getValue().hashCode())
+ * This ensures that {@code e1.equals(e2)} implies that + * {@code e1.hashCode()==e2.hashCode()} for any two Entries + * {@code e1} and {@code e2}, as required by the general + * contract of {@link Object#hashCode}. + * + * @return the hash code value for this map entry + * @see #equals + */ + public int hashCode() { + return (key == null ? 0 : key.hashCode()) ^ + (value == null ? 0 : value.hashCode()); + } + + /** + * Returns a String representation of this map entry. This + * implementation returns the string representation of this + * entry's key followed by the equals character ("=") + * followed by the string representation of this entry's value. + * + * @return a String representation of this map entry + */ + public String toString() { + return key + "=" + value; + } + + } + + /** + * An Entry maintaining an immutable key and value. This class + * does not support method setValue. This class may be + * convenient in methods that return thread-safe snapshots of + * key-value mappings. + * + * @since 1.6 + */ + public static class SimpleImmutableEntry + implements Entry, java.io.Serializable + { + private static final long serialVersionUID = 7138329143949025153L; + + private final K key; + private final V value; + + /** + * Creates an entry representing a mapping from the specified + * key to the specified value. + * + * @param key the key represented by this entry + * @param value the value represented by this entry + */ + public SimpleImmutableEntry(K key, V value) { + this.key = key; + this.value = value; + } + + /** + * Creates an entry representing the same mapping as the + * specified entry. + * + * @param entry the entry to copy + */ + public SimpleImmutableEntry(Entry entry) { + this.key = entry.getKey(); + this.value = entry.getValue(); + } + + /** + * Returns the key corresponding to this entry. + * + * @return the key corresponding to this entry + */ + public K getKey() { + return key; + } + + /** + * Returns the value corresponding to this entry. + * + * @return the value corresponding to this entry + */ + public V getValue() { + return value; + } + + /** + * Replaces the value corresponding to this entry with the specified + * value (optional operation). This implementation simply throws + * UnsupportedOperationException, as this class implements + * an immutable map entry. + * + * @param value new value to be stored in this entry + * @return (Does not return) + * @throws UnsupportedOperationException always + */ + public V setValue(V value) { + throw new UnsupportedOperationException(); + } + + /** + * Compares the specified object with this entry for equality. + * Returns {@code true} if the given object is also a map entry and + * the two entries represent the same mapping. More formally, two + * entries {@code e1} and {@code e2} represent the same mapping + * if
+         *   (e1.getKey()==null ?
+         *    e2.getKey()==null :
+         *    e1.getKey().equals(e2.getKey()))
+         *   &&
+         *   (e1.getValue()==null ?
+         *    e2.getValue()==null :
+         *    e1.getValue().equals(e2.getValue()))
+ * This ensures that the {@code equals} method works properly across + * different implementations of the {@code Map.Entry} interface. + * + * @param o object to be compared for equality with this map entry + * @return {@code true} if the specified object is equal to this map + * entry + * @see #hashCode + */ + public boolean equals(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry e = (Map.Entry)o; + return eq(key, e.getKey()) && eq(value, e.getValue()); + } + + /** + * Returns the hash code value for this map entry. The hash code + * of a map entry {@code e} is defined to be:
+         *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
+         *   (e.getValue()==null ? 0 : e.getValue().hashCode())
+ * This ensures that {@code e1.equals(e2)} implies that + * {@code e1.hashCode()==e2.hashCode()} for any two Entries + * {@code e1} and {@code e2}, as required by the general + * contract of {@link Object#hashCode}. + * + * @return the hash code value for this map entry + * @see #equals + */ + public int hashCode() { + return (key == null ? 0 : key.hashCode()) ^ + (value == null ? 0 : value.hashCode()); + } + + /** + * Returns a String representation of this map entry. This + * implementation returns the string representation of this + * entry's key followed by the equals character ("=") + * followed by the string representation of this entry's value. + * + * @return a String representation of this map entry + */ + public String toString() { + return key + "=" + value; + } + + } + +} \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/util/java7_util/AbstractSet7.java b/src/ooxml/java/org/apache/poi/util/java7_util/AbstractSet7.java new file mode 100644 index 000000000..bb4fe0011 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/util/java7_util/AbstractSet7.java @@ -0,0 +1,190 @@ +/* + * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.apache.poi.util.java7_util; + +import java.util.AbstractCollection; +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; + +/** + * This class provides a skeletal implementation of the Set + * interface to minimize the effort required to implement this + * interface.

+ * + * The process of implementing a set by extending this class is identical + * to that of implementing a Collection by extending AbstractCollection, + * except that all of the methods and constructors in subclasses of this + * class must obey the additional constraints imposed by the Set + * interface (for instance, the add method must not permit addition of + * multiple instances of an object to a set).

+ * + * Note that this class does not override any of the implementations from + * the AbstractCollection class. It merely adds implementations + * for equals and hashCode.

+ * + * This class is a member of the + * + * Java Collections Framework. + * + * @param the type of elements maintained by this set + * + * @author Josh Bloch + * @author Neal Gafter + * @see Collection + * @see AbstractCollection + * @see Set + * @since 1.2 + */ + +public abstract class AbstractSet7 extends AbstractCollection implements Set { + /** + * Sole constructor. (For invocation by subclass constructors, typically + * implicit.) + */ + protected AbstractSet7() { + } + + // Comparison and hashing + + /** + * Compares the specified object with this set for equality. Returns + * true if the given object is also a set, the two sets have + * the same size, and every member of the given set is contained in + * this set. This ensures that the equals method works + * properly across different implementations of the Set + * interface.

+ * + * This implementation first checks if the specified object is this + * set; if so it returns true. Then, it checks if the + * specified object is a set whose size is identical to the size of + * this set; if not, it returns false. If so, it returns + * containsAll((Collection) o). + * + * @param o object to be compared for equality with this set + * @return true if the specified object is equal to this set + */ + public boolean equals(Object o) { + if (o == this) + return true; + + if (!(o instanceof Set)) + return false; + Collection c = (Collection) o; + if (c.size() != size()) + return false; + try { + return containsAll(c); + } catch (ClassCastException unused) { + return false; + } catch (NullPointerException unused) { + return false; + } + } + + /** + * Returns the hash code value for this set. The hash code of a set is + * defined to be the sum of the hash codes of the elements in the set, + * where the hash code of a null element is defined to be zero. + * This ensures that s1.equals(s2) implies that + * s1.hashCode()==s2.hashCode() for any two sets s1 + * and s2, as required by the general contract of + * {@link Object#hashCode}. + * + *

This implementation iterates over the set, calling the + * hashCode method on each element in the set, and adding up + * the results. + * + * @return the hash code value for this set + * @see Object#equals(Object) + * @see Set#equals(Object) + */ + public int hashCode() { + int h = 0; + Iterator i = iterator(); + while (i.hasNext()) { + E obj = i.next(); + if (obj != null) + h += obj.hashCode(); + } + return h; + } + + /** + * Removes from this set all of its elements that are contained in the + * specified collection (optional operation). If the specified + * collection is also a set, this operation effectively modifies this + * set so that its value is the asymmetric set difference of + * the two sets. + * + *

This implementation determines which is the smaller of this set + * and the specified collection, by invoking the size + * method on each. If this set has fewer elements, then the + * implementation iterates over this set, checking each element + * returned by the iterator in turn to see if it is contained in + * the specified collection. If it is so contained, it is removed + * from this set with the iterator's remove method. If + * the specified collection has fewer elements, then the + * implementation iterates over the specified collection, removing + * from this set each element returned by the iterator, using this + * set's remove method. + * + *

Note that this implementation will throw an + * UnsupportedOperationException if the iterator returned by the + * iterator method does not implement the remove method. + * + * @param c collection containing elements to be removed from this set + * @return true if this set changed as a result of the call + * @throws UnsupportedOperationException if the removeAll operation + * is not supported by this set + * @throws ClassCastException if the class of an element of this set + * is incompatible with the specified collection + * (optional) + * @throws NullPointerException if this set contains a null element and the + * specified collection does not permit null elements + * (optional), + * or if the specified collection is null + * @see #remove(Object) + * @see #contains(Object) + */ + public boolean removeAll(Collection c) { + boolean modified = false; + + if (size() > c.size()) { + for (Iterator i = c.iterator(); i.hasNext(); ) + modified |= remove(i.next()); + } else { + for (Iterator i = iterator(); i.hasNext(); ) { + if (c.contains(i.next())) { + i.remove(); + modified = true; + } + } + } + return modified; + } + +} \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/util/java7_util/NavigableMap7.java b/src/ooxml/java/org/apache/poi/util/java7_util/NavigableMap7.java new file mode 100644 index 000000000..45150d5b7 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/util/java7_util/NavigableMap7.java @@ -0,0 +1,429 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea and Josh Bloch with assistance from members of JCP + * JSR-166 Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package org.apache.poi.util.java7_util; + +import java.util.Collections; +import java.util.Comparator; +import java.util.Map; +import java.util.SortedMap; + +/** + * A {@link SortedMap} extended with navigation methods returning the + * closest matches for given search targets. Methods + * {@code lowerEntry}, {@code floorEntry}, {@code ceilingEntry}, + * and {@code higherEntry} return {@code Map.Entry} objects + * associated with keys respectively less than, less than or equal, + * greater than or equal, and greater than a given key, returning + * {@code null} if there is no such key. Similarly, methods + * {@code lowerKey}, {@code floorKey}, {@code ceilingKey}, and + * {@code higherKey} return only the associated keys. All of these + * methods are designed for locating, not traversing entries. + * + *

A {@code NavigableMap7} may be accessed and traversed in either + * ascending or descending key order. The {@code descendingMap} + * method returns a view of the map with the senses of all relational + * and directional methods inverted. The performance of ascending + * operations and views is likely to be faster than that of descending + * ones. Methods {@code subMap}, {@code headMap}, + * and {@code tailMap} differ from the like-named {@code + * SortedMap} methods in accepting additional arguments describing + * whether lower and upper bounds are inclusive versus exclusive. + * Submaps of any {@code NavigableMap7} must implement the {@code + * NavigableMap7} interface. + * + *

This interface additionally defines methods {@code firstEntry}, + * {@code pollFirstEntry}, {@code lastEntry}, and + * {@code pollLastEntry} that return and/or remove the least and + * greatest mappings, if any exist, else returning {@code null}. + * + *

Implementations of entry-returning methods are expected to + * return {@code Map.Entry} pairs representing snapshots of mappings + * at the time they were produced, and thus generally do not + * support the optional {@code Entry.setValue} method. Note however + * that it is possible to change mappings in the associated map using + * method {@code put}. + * + *

Methods + * {@link #subMap(Object, Object) subMap(K, K)}, + * {@link #headMap(Object) headMap(K)}, and + * {@link #tailMap(Object) tailMap(K)} + * are specified to return {@code SortedMap} to allow existing + * implementations of {@code SortedMap} to be compatibly retrofitted to + * implement {@code NavigableMap7}, but extensions and implementations + * of this interface are encouraged to override these methods to return + * {@code NavigableMap7}. Similarly, + * {@link #keySet()} can be overriden to return {@code NavigableSet}. + * + *

This interface is a member of the + * + * Java Collections Framework. + * + * @author Doug Lea + * @author Josh Bloch + * @param the type of keys maintained by this map + * @param the type of mapped values + * @since 1.6 + */ +public interface NavigableMap7 extends SortedMap { + /** + * Returns a key-value mapping associated with the greatest key + * strictly less than the given key, or {@code null} if there is + * no such key. + * + * @param key the key + * @return an entry with the greatest key less than {@code key}, + * or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + Map.Entry lowerEntry(K key); + + /** + * Returns the greatest key strictly less than the given key, or + * {@code null} if there is no such key. + * + * @param key the key + * @return the greatest key less than {@code key}, + * or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + K lowerKey(K key); + + /** + * Returns a key-value mapping associated with the greatest key + * less than or equal to the given key, or {@code null} if there + * is no such key. + * + * @param key the key + * @return an entry with the greatest key less than or equal to + * {@code key}, or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + Map.Entry floorEntry(K key); + + /** + * Returns the greatest key less than or equal to the given key, + * or {@code null} if there is no such key. + * + * @param key the key + * @return the greatest key less than or equal to {@code key}, + * or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + K floorKey(K key); + + /** + * Returns a key-value mapping associated with the least key + * greater than or equal to the given key, or {@code null} if + * there is no such key. + * + * @param key the key + * @return an entry with the least key greater than or equal to + * {@code key}, or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + Map.Entry ceilingEntry(K key); + + /** + * Returns the least key greater than or equal to the given key, + * or {@code null} if there is no such key. + * + * @param key the key + * @return the least key greater than or equal to {@code key}, + * or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + K ceilingKey(K key); + + /** + * Returns a key-value mapping associated with the least key + * strictly greater than the given key, or {@code null} if there + * is no such key. + * + * @param key the key + * @return an entry with the least key greater than {@code key}, + * or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + Map.Entry higherEntry(K key); + + /** + * Returns the least key strictly greater than the given key, or + * {@code null} if there is no such key. + * + * @param key the key + * @return the least key greater than {@code key}, + * or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + K higherKey(K key); + + /** + * Returns a key-value mapping associated with the least + * key in this map, or {@code null} if the map is empty. + * + * @return an entry with the least key, + * or {@code null} if this map is empty + */ + Map.Entry firstEntry(); + + /** + * Returns a key-value mapping associated with the greatest + * key in this map, or {@code null} if the map is empty. + * + * @return an entry with the greatest key, + * or {@code null} if this map is empty + */ + Map.Entry lastEntry(); + + /** + * Removes and returns a key-value mapping associated with + * the least key in this map, or {@code null} if the map is empty. + * + * @return the removed first entry of this map, + * or {@code null} if this map is empty + */ + Map.Entry pollFirstEntry(); + + /** + * Removes and returns a key-value mapping associated with + * the greatest key in this map, or {@code null} if the map is empty. + * + * @return the removed last entry of this map, + * or {@code null} if this map is empty + */ + Map.Entry pollLastEntry(); + + /** + * Returns a reverse order view of the mappings contained in this map. + * The descending map is backed by this map, so changes to the map are + * reflected in the descending map, and vice-versa. If either map is + * modified while an iteration over a collection view of either map + * is in progress (except through the iterator's own {@code remove} + * operation), the results of the iteration are undefined. + * + *

The returned map has an ordering equivalent to + * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator()). + * The expression {@code m.descendingMap().descendingMap()} returns a + * view of {@code m} essentially equivalent to {@code m}. + * + * @return a reverse order view of this map + */ + NavigableMap7 descendingMap(); + + /** + * Returns a {@link NavigableSet} view of the keys contained in this map. + * The set's iterator returns the keys in ascending order. + * The set is backed by the map, so changes to the map are reflected in + * the set, and vice-versa. If the map is modified while an iteration + * over the set is in progress (except through the iterator's own {@code + * remove} operation), the results of the iteration are undefined. The + * set supports element removal, which removes the corresponding mapping + * from the map, via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} operations. + * It does not support the {@code add} or {@code addAll} operations. + * + * @return a navigable set view of the keys in this map + */ + NavigableSet7 navigableKeySet(); + + /** + * Returns a reverse order {@link NavigableSet} view of the keys contained in this map. + * The set's iterator returns the keys in descending order. + * The set is backed by the map, so changes to the map are reflected in + * the set, and vice-versa. If the map is modified while an iteration + * over the set is in progress (except through the iterator's own {@code + * remove} operation), the results of the iteration are undefined. The + * set supports element removal, which removes the corresponding mapping + * from the map, via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} operations. + * It does not support the {@code add} or {@code addAll} operations. + * + * @return a reverse order navigable set view of the keys in this map + */ + NavigableSet7 descendingKeySet(); + + /** + * Returns a view of the portion of this map whose keys range from + * {@code fromKey} to {@code toKey}. If {@code fromKey} and + * {@code toKey} are equal, the returned map is empty unless + * {@code fromInclusive} and {@code toInclusive} are both true. The + * returned map is backed by this map, so changes in the returned map are + * reflected in this map, and vice-versa. The returned map supports all + * optional map operations that this map supports. + * + *

The returned map will throw an {@code IllegalArgumentException} + * on an attempt to insert a key outside of its range, or to construct a + * submap either of whose endpoints lie outside its range. + * + * @param fromKey low endpoint of the keys in the returned map + * @param fromInclusive {@code true} if the low endpoint + * is to be included in the returned view + * @param toKey high endpoint of the keys in the returned map + * @param toInclusive {@code true} if the high endpoint + * is to be included in the returned view + * @return a view of the portion of this map whose keys range from + * {@code fromKey} to {@code toKey} + * @throws ClassCastException if {@code fromKey} and {@code toKey} + * cannot be compared to one another using this map's comparator + * (or, if the map has no comparator, using natural ordering). + * Implementations may, but are not required to, throw this + * exception if {@code fromKey} or {@code toKey} + * cannot be compared to keys currently in the map. + * @throws NullPointerException if {@code fromKey} or {@code toKey} + * is null and this map does not permit null keys + * @throws IllegalArgumentException if {@code fromKey} is greater than + * {@code toKey}; or if this map itself has a restricted + * range, and {@code fromKey} or {@code toKey} lies + * outside the bounds of the range + */ + NavigableMap7 subMap(K fromKey, boolean fromInclusive, + K toKey, boolean toInclusive); + + /** + * Returns a view of the portion of this map whose keys are less than (or + * equal to, if {@code inclusive} is true) {@code toKey}. The returned + * map is backed by this map, so changes in the returned map are reflected + * in this map, and vice-versa. The returned map supports all optional + * map operations that this map supports. + * + *

The returned map will throw an {@code IllegalArgumentException} + * on an attempt to insert a key outside its range. + * + * @param toKey high endpoint of the keys in the returned map + * @param inclusive {@code true} if the high endpoint + * is to be included in the returned view + * @return a view of the portion of this map whose keys are less than + * (or equal to, if {@code inclusive} is true) {@code toKey} + * @throws ClassCastException if {@code toKey} is not compatible + * with this map's comparator (or, if the map has no comparator, + * if {@code toKey} does not implement {@link Comparable}). + * Implementations may, but are not required to, throw this + * exception if {@code toKey} cannot be compared to keys + * currently in the map. + * @throws NullPointerException if {@code toKey} is null + * and this map does not permit null keys + * @throws IllegalArgumentException if this map itself has a + * restricted range, and {@code toKey} lies outside the + * bounds of the range + */ + NavigableMap7 headMap(K toKey, boolean inclusive); + + /** + * Returns a view of the portion of this map whose keys are greater than (or + * equal to, if {@code inclusive} is true) {@code fromKey}. The returned + * map is backed by this map, so changes in the returned map are reflected + * in this map, and vice-versa. The returned map supports all optional + * map operations that this map supports. + * + *

The returned map will throw an {@code IllegalArgumentException} + * on an attempt to insert a key outside its range. + * + * @param fromKey low endpoint of the keys in the returned map + * @param inclusive {@code true} if the low endpoint + * is to be included in the returned view + * @return a view of the portion of this map whose keys are greater than + * (or equal to, if {@code inclusive} is true) {@code fromKey} + * @throws ClassCastException if {@code fromKey} is not compatible + * with this map's comparator (or, if the map has no comparator, + * if {@code fromKey} does not implement {@link Comparable}). + * Implementations may, but are not required to, throw this + * exception if {@code fromKey} cannot be compared to keys + * currently in the map. + * @throws NullPointerException if {@code fromKey} is null + * and this map does not permit null keys + * @throws IllegalArgumentException if this map itself has a + * restricted range, and {@code fromKey} lies outside the + * bounds of the range + */ + NavigableMap7 tailMap(K fromKey, boolean inclusive); + + /** + * {@inheritDoc} + * + *

Equivalent to {@code subMap(fromKey, true, toKey, false)}. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + SortedMap subMap(K fromKey, K toKey); + + /** + * {@inheritDoc} + * + *

Equivalent to {@code headMap(toKey, false)}. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + SortedMap headMap(K toKey); + + /** + * {@inheritDoc} + * + *

Equivalent to {@code tailMap(fromKey, true)}. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + SortedMap tailMap(K fromKey); +} \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/util/java7_util/NavigableSet7.java b/src/ooxml/java/org/apache/poi/util/java7_util/NavigableSet7.java new file mode 100644 index 000000000..bc515e727 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/util/java7_util/NavigableSet7.java @@ -0,0 +1,324 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea and Josh Bloch with assistance from members of JCP + * JSR-166 Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package org.apache.poi.util.java7_util; + +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.SortedSet; + +/** + * A {@link SortedSet} extended with navigation methods reporting + * closest matches for given search targets. Methods {@code lower}, + * {@code floor}, {@code ceiling}, and {@code higher} return elements + * respectively less than, less than or equal, greater than or equal, + * and greater than a given element, returning {@code null} if there + * is no such element. A {@code NavigableSet7} may be accessed and + * traversed in either ascending or descending order. The {@code + * descendingSet} method returns a view of the set with the senses of + * all relational and directional methods inverted. The performance of + * ascending operations and views is likely to be faster than that of + * descending ones. This interface additionally defines methods + * {@code pollFirst} and {@code pollLast} that return and remove the + * lowest and highest element, if one exists, else returning {@code + * null}. Methods {@code subSet}, {@code headSet}, + * and {@code tailSet} differ from the like-named {@code + * SortedSet} methods in accepting additional arguments describing + * whether lower and upper bounds are inclusive versus exclusive. + * Subsets of any {@code NavigableSet7} must implement the {@code + * NavigableSet7} interface. + * + *

The return values of navigation methods may be ambiguous in + * implementations that permit {@code null} elements. However, even + * in this case the result can be disambiguated by checking + * {@code contains(null)}. To avoid such issues, implementations of + * this interface are encouraged to not permit insertion of + * {@code null} elements. (Note that sorted sets of {@link + * Comparable} elements intrinsically do not permit {@code null}.) + * + *

Methods + * {@link #subSet(Object, Object) subSet(E, E)}, + * {@link #headSet(Object) headSet(E)}, and + * {@link #tailSet(Object) tailSet(E)} + * are specified to return {@code SortedSet} to allow existing + * implementations of {@code SortedSet} to be compatibly retrofitted to + * implement {@code NavigableSet7}, but extensions and implementations + * of this interface are encouraged to override these methods to return + * {@code NavigableSet7}. + * + *

This interface is a member of the + * + * Java Collections Framework. + * + * @author Doug Lea + * @author Josh Bloch + * @param the type of elements maintained by this set + * @since 1.6 + */ +public interface NavigableSet7 extends SortedSet { + /** + * Returns the greatest element in this set strictly less than the + * given element, or {@code null} if there is no such element. + * + * @param e the value to match + * @return the greatest element less than {@code e}, + * or {@code null} if there is no such element + * @throws ClassCastException if the specified element cannot be + * compared with the elements currently in the set + * @throws NullPointerException if the specified element is null + * and this set does not permit null elements + */ + E lower(E e); + + /** + * Returns the greatest element in this set less than or equal to + * the given element, or {@code null} if there is no such element. + * + * @param e the value to match + * @return the greatest element less than or equal to {@code e}, + * or {@code null} if there is no such element + * @throws ClassCastException if the specified element cannot be + * compared with the elements currently in the set + * @throws NullPointerException if the specified element is null + * and this set does not permit null elements + */ + E floor(E e); + + /** + * Returns the least element in this set greater than or equal to + * the given element, or {@code null} if there is no such element. + * + * @param e the value to match + * @return the least element greater than or equal to {@code e}, + * or {@code null} if there is no such element + * @throws ClassCastException if the specified element cannot be + * compared with the elements currently in the set + * @throws NullPointerException if the specified element is null + * and this set does not permit null elements + */ + E ceiling(E e); + + /** + * Returns the least element in this set strictly greater than the + * given element, or {@code null} if there is no such element. + * + * @param e the value to match + * @return the least element greater than {@code e}, + * or {@code null} if there is no such element + * @throws ClassCastException if the specified element cannot be + * compared with the elements currently in the set + * @throws NullPointerException if the specified element is null + * and this set does not permit null elements + */ + E higher(E e); + + /** + * Retrieves and removes the first (lowest) element, + * or returns {@code null} if this set is empty. + * + * @return the first element, or {@code null} if this set is empty + */ + E pollFirst(); + + /** + * Retrieves and removes the last (highest) element, + * or returns {@code null} if this set is empty. + * + * @return the last element, or {@code null} if this set is empty + */ + E pollLast(); + + /** + * Returns an iterator over the elements in this set, in ascending order. + * + * @return an iterator over the elements in this set, in ascending order + */ + Iterator iterator(); + + /** + * Returns a reverse order view of the elements contained in this set. + * The descending set is backed by this set, so changes to the set are + * reflected in the descending set, and vice-versa. If either set is + * modified while an iteration over either set is in progress (except + * through the iterator's own {@code remove} operation), the results of + * the iteration are undefined. + * + *

The returned set has an ordering equivalent to + * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator()). + * The expression {@code s.descendingSet().descendingSet()} returns a + * view of {@code s} essentially equivalent to {@code s}. + * + * @return a reverse order view of this set + */ + NavigableSet7 descendingSet(); + + /** + * Returns an iterator over the elements in this set, in descending order. + * Equivalent in effect to {@code descendingSet().iterator()}. + * + * @return an iterator over the elements in this set, in descending order + */ + Iterator descendingIterator(); + + /** + * Returns a view of the portion of this set whose elements range from + * {@code fromElement} to {@code toElement}. If {@code fromElement} and + * {@code toElement} are equal, the returned set is empty unless {@code + * fromInclusive} and {@code toInclusive} are both true. The returned set + * is backed by this set, so changes in the returned set are reflected in + * this set, and vice-versa. The returned set supports all optional set + * operations that this set supports. + * + *

The returned set will throw an {@code IllegalArgumentException} + * on an attempt to insert an element outside its range. + * + * @param fromElement low endpoint of the returned set + * @param fromInclusive {@code true} if the low endpoint + * is to be included in the returned view + * @param toElement high endpoint of the returned set + * @param toInclusive {@code true} if the high endpoint + * is to be included in the returned view + * @return a view of the portion of this set whose elements range from + * {@code fromElement}, inclusive, to {@code toElement}, exclusive + * @throws ClassCastException if {@code fromElement} and + * {@code toElement} cannot be compared to one another using this + * set's comparator (or, if the set has no comparator, using + * natural ordering). Implementations may, but are not required + * to, throw this exception if {@code fromElement} or + * {@code toElement} cannot be compared to elements currently in + * the set. + * @throws NullPointerException if {@code fromElement} or + * {@code toElement} is null and this set does + * not permit null elements + * @throws IllegalArgumentException if {@code fromElement} is + * greater than {@code toElement}; or if this set itself + * has a restricted range, and {@code fromElement} or + * {@code toElement} lies outside the bounds of the range. + */ + NavigableSet7 subSet(E fromElement, boolean fromInclusive, + E toElement, boolean toInclusive); + + /** + * Returns a view of the portion of this set whose elements are less than + * (or equal to, if {@code inclusive} is true) {@code toElement}. The + * returned set is backed by this set, so changes in the returned set are + * reflected in this set, and vice-versa. The returned set supports all + * optional set operations that this set supports. + * + *

The returned set will throw an {@code IllegalArgumentException} + * on an attempt to insert an element outside its range. + * + * @param toElement high endpoint of the returned set + * @param inclusive {@code true} if the high endpoint + * is to be included in the returned view + * @return a view of the portion of this set whose elements are less than + * (or equal to, if {@code inclusive} is true) {@code toElement} + * @throws ClassCastException if {@code toElement} is not compatible + * with this set's comparator (or, if the set has no comparator, + * if {@code toElement} does not implement {@link Comparable}). + * Implementations may, but are not required to, throw this + * exception if {@code toElement} cannot be compared to elements + * currently in the set. + * @throws NullPointerException if {@code toElement} is null and + * this set does not permit null elements + * @throws IllegalArgumentException if this set itself has a + * restricted range, and {@code toElement} lies outside the + * bounds of the range + */ + NavigableSet7 headSet(E toElement, boolean inclusive); + + /** + * Returns a view of the portion of this set whose elements are greater + * than (or equal to, if {@code inclusive} is true) {@code fromElement}. + * The returned set is backed by this set, so changes in the returned set + * are reflected in this set, and vice-versa. The returned set supports + * all optional set operations that this set supports. + * + *

The returned set will throw an {@code IllegalArgumentException} + * on an attempt to insert an element outside its range. + * + * @param fromElement low endpoint of the returned set + * @param inclusive {@code true} if the low endpoint + * is to be included in the returned view + * @return a view of the portion of this set whose elements are greater + * than or equal to {@code fromElement} + * @throws ClassCastException if {@code fromElement} is not compatible + * with this set's comparator (or, if the set has no comparator, + * if {@code fromElement} does not implement {@link Comparable}). + * Implementations may, but are not required to, throw this + * exception if {@code fromElement} cannot be compared to elements + * currently in the set. + * @throws NullPointerException if {@code fromElement} is null + * and this set does not permit null elements + * @throws IllegalArgumentException if this set itself has a + * restricted range, and {@code fromElement} lies outside the + * bounds of the range + */ + NavigableSet7 tailSet(E fromElement, boolean inclusive); + + /** + * {@inheritDoc} + * + *

Equivalent to {@code subSet(fromElement, true, toElement, false)}. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + SortedSet subSet(E fromElement, E toElement); + + /** + * {@inheritDoc} + * + *

Equivalent to {@code headSet(toElement, false)}. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} +na */ + SortedSet headSet(E toElement); + + /** + * {@inheritDoc} + * + *

Equivalent to {@code tailSet(fromElement, true)}. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + SortedSet tailSet(E fromElement); +} \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/util/java7_util/TreeMap7.java b/src/ooxml/java/org/apache/poi/util/java7_util/TreeMap7.java new file mode 100644 index 000000000..591d8fb6d --- /dev/null +++ b/src/ooxml/java/org/apache/poi/util/java7_util/TreeMap7.java @@ -0,0 +1,2458 @@ +/* + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.apache.poi.util.java7_util; + +import java.io.IOException; +import java.util.AbstractCollection; +import java.util.AbstractSet; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.ConcurrentModificationException; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.SortedMap; +import java.util.SortedSet; + +/** + * A Red-Black tree based {@link NavigableMap7} implementation. + * The map is sorted according to the {@linkplain Comparable natural + * ordering} of its keys, or by a {@link Comparator} provided at map + * creation time, depending on which constructor is used. + * + *

This implementation provides guaranteed log(n) time cost for the + * {@code containsKey}, {@code get}, {@code put} and {@code remove} + * operations. Algorithms are adaptations of those in Cormen, Leiserson, and + * Rivest's Introduction to Algorithms. + * + *

Note that the ordering maintained by a tree map, like any sorted map, and + * whether or not an explicit comparator is provided, must be consistent + * with {@code equals} if this sorted map is to correctly implement the + * {@code Map} interface. (See {@code Comparable} or {@code Comparator} for a + * precise definition of consistent with equals.) This is so because + * the {@code Map} interface is defined in terms of the {@code equals} + * operation, but a sorted map performs all key comparisons using its {@code + * compareTo} (or {@code compare}) method, so two keys that are deemed equal by + * this method are, from the standpoint of the sorted map, equal. The behavior + * of a sorted map is well-defined even if its ordering is + * inconsistent with {@code equals}; it just fails to obey the general contract + * of the {@code Map} interface. + * + *

Note that this implementation is not synchronized. + * If multiple threads access a map concurrently, and at least one of the + * threads modifies the map structurally, it must be synchronized + * externally. (A structural modification is any operation that adds or + * deletes one or more mappings; merely changing the value associated + * with an existing key is not a structural modification.) This is + * typically accomplished by synchronizing on some object that naturally + * encapsulates the map. + * If no such object exists, the map should be "wrapped" using the + * {@link Collections#synchronizedSortedMap Collections.synchronizedSortedMap} + * method. This is best done at creation time, to prevent accidental + * unsynchronized access to the map:

+ *   SortedMap m = Collections.synchronizedSortedMap(new TreeMap7(...));
+ * + *

The iterators returned by the {@code iterator} method of the collections + * returned by all of this class's "collection view methods" are + * fail-fast: if the map is structurally modified at any time after + * the iterator is created, in any way except through the iterator's own + * {@code remove} method, the iterator will throw a {@link + * ConcurrentModificationException}. Thus, in the face of concurrent + * modification, the iterator fails quickly and cleanly, rather than risking + * arbitrary, non-deterministic behavior at an undetermined time in the future. + * + *

Note that the fail-fast behavior of an iterator cannot be guaranteed + * as it is, generally speaking, impossible to make any hard guarantees in the + * presence of unsynchronized concurrent modification. Fail-fast iterators + * throw {@code ConcurrentModificationException} on a best-effort basis. + * Therefore, it would be wrong to write a program that depended on this + * exception for its correctness: the fail-fast behavior of iterators + * should be used only to detect bugs. + * + *

All {@code Map.Entry} pairs returned by methods in this class + * and its views represent snapshots of mappings at the time they were + * produced. They do not support the {@code Entry.setValue} + * method. (Note however that it is possible to change mappings in the + * associated map using {@code put}.) + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @param the type of keys maintained by this map + * @param the type of mapped values + * + * @author Josh Bloch and Doug Lea + * @see Map + * @see HashMap + * @see Hashtable + * @see Comparable + * @see Comparator + * @see Collection + * @since 1.2 + */ + +public class TreeMap7 + extends AbstractMap7 + implements NavigableMap7, Cloneable, java.io.Serializable +{ + /** + * The comparator used to maintain order in this tree map, or + * null if it uses the natural ordering of its keys. + * + * @serial + */ + private final Comparator comparator; + + private transient Entry root = null; + + /** + * The number of entries in the tree + */ + private transient int size = 0; + + /** + * The number of structural modifications to the tree. + */ + private transient int modCount = 0; + + /** + * Constructs a new, empty tree map, using the natural ordering of its + * keys. All keys inserted into the map must implement the {@link + * Comparable} interface. Furthermore, all such keys must be + * mutually comparable: {@code k1.compareTo(k2)} must not throw + * a {@code ClassCastException} for any keys {@code k1} and + * {@code k2} in the map. If the user attempts to put a key into the + * map that violates this constraint (for example, the user attempts to + * put a string key into a map whose keys are integers), the + * {@code put(Object key, Object value)} call will throw a + * {@code ClassCastException}. + */ + public TreeMap7() { + comparator = null; + } + + /** + * Constructs a new, empty tree map, ordered according to the given + * comparator. All keys inserted into the map must be mutually + * comparable by the given comparator: {@code comparator.compare(k1, + * k2)} must not throw a {@code ClassCastException} for any keys + * {@code k1} and {@code k2} in the map. If the user attempts to put + * a key into the map that violates this constraint, the {@code put(Object + * key, Object value)} call will throw a + * {@code ClassCastException}. + * + * @param comparator the comparator that will be used to order this map. + * If {@code null}, the {@linkplain Comparable natural + * ordering} of the keys will be used. + */ + public TreeMap7(Comparator comparator) { + this.comparator = comparator; + } + + /** + * Constructs a new tree map containing the same mappings as the given + * map, ordered according to the natural ordering of its keys. + * All keys inserted into the new map must implement the {@link + * Comparable} interface. Furthermore, all such keys must be + * mutually comparable: {@code k1.compareTo(k2)} must not throw + * a {@code ClassCastException} for any keys {@code k1} and + * {@code k2} in the map. This method runs in n*log(n) time. + * + * @param m the map whose mappings are to be placed in this map + * @throws ClassCastException if the keys in m are not {@link Comparable}, + * or are not mutually comparable + * @throws NullPointerException if the specified map is null + */ + public TreeMap7(Map m) { + comparator = null; + putAll(m); + } + + /** + * Constructs a new tree map containing the same mappings and + * using the same ordering as the specified sorted map. This + * method runs in linear time. + * + * @param m the sorted map whose mappings are to be placed in this map, + * and whose comparator is to be used to sort this map + * @throws NullPointerException if the specified map is null + */ + public TreeMap7(SortedMap m) { + comparator = m.comparator(); + try { + buildFromSorted(m.size(), m.entrySet().iterator(), null, null); + } catch (java.io.IOException cannotHappen) { + } catch (ClassNotFoundException cannotHappen) { + } + } + + + // Query Operations + + /** + * Returns the number of key-value mappings in this map. + * + * @return the number of key-value mappings in this map + */ + public int size() { + return size; + } + + /** + * Returns {@code true} if this map contains a mapping for the specified + * key. + * + * @param key key whose presence in this map is to be tested + * @return {@code true} if this map contains a mapping for the + * specified key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + */ + public boolean containsKey(Object key) { + return getEntry(key) != null; + } + + /** + * Returns {@code true} if this map maps one or more keys to the + * specified value. More formally, returns {@code true} if and only if + * this map contains at least one mapping to a value {@code v} such + * that {@code (value==null ? v==null : value.equals(v))}. This + * operation will probably require time linear in the map size for + * most implementations. + * + * @param value value whose presence in this map is to be tested + * @return {@code true} if a mapping to {@code value} exists; + * {@code false} otherwise + * @since 1.2 + */ + public boolean containsValue(Object value) { + for (Entry e = getFirstEntry(); e != null; e = successor(e)) + if (valEquals(value, e.value)) + return true; + return false; + } + + /** + * Returns the value to which the specified key is mapped, + * or {@code null} if this map contains no mapping for the key. + * + *

More formally, if this map contains a mapping from a key + * {@code k} to a value {@code v} such that {@code key} compares + * equal to {@code k} according to the map's ordering, then this + * method returns {@code v}; otherwise it returns {@code null}. + * (There can be at most one such mapping.) + * + *

A return value of {@code null} does not necessarily + * indicate that the map contains no mapping for the key; it's also + * possible that the map explicitly maps the key to {@code null}. + * The {@link #containsKey containsKey} operation may be used to + * distinguish these two cases. + * + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + */ + public V get(Object key) { + Entry p = getEntry(key); + return (p==null ? null : p.value); + } + + public Comparator comparator() { + return comparator; + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public K firstKey() { + return key(getFirstEntry()); + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public K lastKey() { + return key(getLastEntry()); + } + + /** + * Copies all of the mappings from the specified map to this map. + * These mappings replace any mappings that this map had for any + * of the keys currently in the specified map. + * + * @param map mappings to be stored in this map + * @throws ClassCastException if the class of a key or value in + * the specified map prevents it from being stored in this map + * @throws NullPointerException if the specified map is null or + * the specified map contains a null key and this map does not + * permit null keys + */ + public void putAll(Map map) { + int mapSize = map.size(); + if (size==0 && mapSize!=0 && map instanceof SortedMap) { + Comparator c = ((SortedMap)map).comparator(); + if (c == comparator || (c != null && c.equals(comparator))) { + ++modCount; + try { + buildFromSorted(mapSize, map.entrySet().iterator(), + null, null); + } catch (java.io.IOException cannotHappen) { + } catch (ClassNotFoundException cannotHappen) { + } + return; + } + } + super.putAll(map); + } + + /** + * Returns this map's entry for the given key, or {@code null} if the map + * does not contain an entry for the key. + * + * @return this map's entry for the given key, or {@code null} if the map + * does not contain an entry for the key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + */ + final Entry getEntry(Object key) { + // Offload comparator-based version for sake of performance + if (comparator != null) + return getEntryUsingComparator(key); + if (key == null) + throw new NullPointerException(); + Comparable k = (Comparable) key; + Entry p = root; + while (p != null) { + int cmp = k.compareTo(p.key); + if (cmp < 0) + p = p.left; + else if (cmp > 0) + p = p.right; + else + return p; + } + return null; + } + + /** + * Version of getEntry using comparator. Split off from getEntry + * for performance. (This is not worth doing for most methods, + * that are less dependent on comparator performance, but is + * worthwhile here.) + */ + final Entry getEntryUsingComparator(Object key) { + K k = (K) key; + Comparator cpr = comparator; + if (cpr != null) { + Entry p = root; + while (p != null) { + int cmp = cpr.compare(k, p.key); + if (cmp < 0) + p = p.left; + else if (cmp > 0) + p = p.right; + else + return p; + } + } + return null; + } + + /** + * Gets the entry corresponding to the specified key; if no such entry + * exists, returns the entry for the least key greater than the specified + * key; if no such entry exists (i.e., the greatest key in the Tree is less + * than the specified key), returns {@code null}. + */ + final Entry getCeilingEntry(K key) { + Entry p = root; + while (p != null) { + int cmp = compare(key, p.key); + if (cmp < 0) { + if (p.left != null) + p = p.left; + else + return p; + } else if (cmp > 0) { + if (p.right != null) { + p = p.right; + } else { + Entry parent = p.parent; + Entry ch = p; + while (parent != null && ch == parent.right) { + ch = parent; + parent = parent.parent; + } + return parent; + } + } else + return p; + } + return null; + } + + /** + * Gets the entry corresponding to the specified key; if no such entry + * exists, returns the entry for the greatest key less than the specified + * key; if no such entry exists, returns {@code null}. + */ + final Entry getFloorEntry(K key) { + Entry p = root; + while (p != null) { + int cmp = compare(key, p.key); + if (cmp > 0) { + if (p.right != null) + p = p.right; + else + return p; + } else if (cmp < 0) { + if (p.left != null) { + p = p.left; + } else { + Entry parent = p.parent; + Entry ch = p; + while (parent != null && ch == parent.left) { + ch = parent; + parent = parent.parent; + } + return parent; + } + } else + return p; + + } + return null; + } + + /** + * Gets the entry for the least key greater than the specified + * key; if no such entry exists, returns the entry for the least + * key greater than the specified key; if no such entry exists + * returns {@code null}. + */ + final Entry getHigherEntry(K key) { + Entry p = root; + while (p != null) { + int cmp = compare(key, p.key); + if (cmp < 0) { + if (p.left != null) + p = p.left; + else + return p; + } else { + if (p.right != null) { + p = p.right; + } else { + Entry parent = p.parent; + Entry ch = p; + while (parent != null && ch == parent.right) { + ch = parent; + parent = parent.parent; + } + return parent; + } + } + } + return null; + } + + /** + * Returns the entry for the greatest key less than the specified key; if + * no such entry exists (i.e., the least key in the Tree is greater than + * the specified key), returns {@code null}. + */ + final Entry getLowerEntry(K key) { + Entry p = root; + while (p != null) { + int cmp = compare(key, p.key); + if (cmp > 0) { + if (p.right != null) + p = p.right; + else + return p; + } else { + if (p.left != null) { + p = p.left; + } else { + Entry parent = p.parent; + Entry ch = p; + while (parent != null && ch == parent.left) { + ch = parent; + parent = parent.parent; + } + return parent; + } + } + } + return null; + } + + /** + * Associates the specified value with the specified key in this map. + * If the map previously contained a mapping for the key, the old + * value is replaced. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key}. + * (A {@code null} return can also indicate that the map + * previously associated {@code null} with {@code key}.) + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + */ + public V put(K key, V value) { + Entry t = root; + if (t == null) { + compare(key, key); // type (and possibly null) check + + root = new Entry(key, value, null); + size = 1; + modCount++; + return null; + } + int cmp; + Entry parent; + // split comparator and comparable paths + Comparator cpr = comparator; + if (cpr != null) { + do { + parent = t; + cmp = cpr.compare(key, t.key); + if (cmp < 0) + t = t.left; + else if (cmp > 0) + t = t.right; + else + return t.setValue(value); + } while (t != null); + } + else { + if (key == null) + throw new NullPointerException(); + Comparable k = (Comparable) key; + do { + parent = t; + cmp = k.compareTo(t.key); + if (cmp < 0) + t = t.left; + else if (cmp > 0) + t = t.right; + else + return t.setValue(value); + } while (t != null); + } + Entry e = new Entry(key, value, parent); + if (cmp < 0) + parent.left = e; + else + parent.right = e; + fixAfterInsertion(e); + size++; + modCount++; + return null; + } + + /** + * Removes the mapping for this key from this TreeMap7 if present. + * + * @param key key for which mapping should be removed + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key}. + * (A {@code null} return can also indicate that the map + * previously associated {@code null} with {@code key}.) + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + */ + public V remove(Object key) { + Entry p = getEntry(key); + if (p == null) + return null; + + V oldValue = p.value; + deleteEntry(p); + return oldValue; + } + + /** + * Removes all of the mappings from this map. + * The map will be empty after this call returns. + */ + public void clear() { + modCount++; + size = 0; + root = null; + } + + /** + * Returns a shallow copy of this {@code TreeMap7} instance. (The keys and + * values themselves are not cloned.) + * + * @return a shallow copy of this map + */ + public Object clone() { + TreeMap7 clone = null; + try { + clone = (TreeMap7) super.clone(); + } catch (CloneNotSupportedException e) { + throw new InternalError(); + } + + // Put clone into "virgin" state (except for comparator) + clone.root = null; + clone.size = 0; + clone.modCount = 0; + clone.entrySet = null; + clone.navigableKeySet = null; + clone.descendingMap = null; + + // Initialize clone with our mappings + try { + clone.buildFromSorted(size, entrySet().iterator(), null, null); + } catch (java.io.IOException cannotHappen) { + } catch (ClassNotFoundException cannotHappen) { + } + + return clone; + } + + // NavigableMap7 API methods + + /** + * @since 1.6 + */ + public Map.Entry firstEntry() { + return exportEntry(getFirstEntry()); + } + + /** + * @since 1.6 + */ + public Map.Entry lastEntry() { + return exportEntry(getLastEntry()); + } + + /** + * @since 1.6 + */ + public Map.Entry pollFirstEntry() { + Entry p = getFirstEntry(); + Map.Entry result = exportEntry(p); + if (p != null) + deleteEntry(p); + return result; + } + + /** + * @since 1.6 + */ + public Map.Entry pollLastEntry() { + Entry p = getLastEntry(); + Map.Entry result = exportEntry(p); + if (p != null) + deleteEntry(p); + return result; + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @since 1.6 + */ + public Map.Entry lowerEntry(K key) { + return exportEntry(getLowerEntry(key)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @since 1.6 + */ + public K lowerKey(K key) { + return keyOrNull(getLowerEntry(key)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @since 1.6 + */ + public Map.Entry floorEntry(K key) { + return exportEntry(getFloorEntry(key)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @since 1.6 + */ + public K floorKey(K key) { + return keyOrNull(getFloorEntry(key)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @since 1.6 + */ + public Map.Entry ceilingEntry(K key) { + return exportEntry(getCeilingEntry(key)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @since 1.6 + */ + public K ceilingKey(K key) { + return keyOrNull(getCeilingEntry(key)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @since 1.6 + */ + public Map.Entry higherEntry(K key) { + return exportEntry(getHigherEntry(key)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @since 1.6 + */ + public K higherKey(K key) { + return keyOrNull(getHigherEntry(key)); + } + + // Views + + /** + * Fields initialized to contain an instance of the entry set view + * the first time this view is requested. Views are stateless, so + * there's no reason to create more than one. + */ + private transient EntrySet entrySet = null; + private transient KeySet navigableKeySet = null; + private transient NavigableMap7 descendingMap = null; + + /** + * Returns a {@link Set} view of the keys contained in this map. + * The set's iterator returns the keys in ascending order. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. If the map is modified + * while an iteration over the set is in progress (except through + * the iterator's own {@code remove} operation), the results of + * the iteration are undefined. The set supports element removal, + * which removes the corresponding mapping from the map, via the + * {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or {@code addAll} + * operations. + */ + public Set keySet() { + return navigableKeySet(); + } + + /** + * @since 1.6 + */ + public NavigableSet7 navigableKeySet() { + KeySet nks = navigableKeySet; + return (nks != null) ? nks : (navigableKeySet = new KeySet(this)); + } + + /** + * @since 1.6 + */ + public NavigableSet7 descendingKeySet() { + return descendingMap().navigableKeySet(); + } + + /** + * Returns a {@link Collection} view of the values contained in this map. + * The collection's iterator returns the values in ascending order + * of the corresponding keys. + * The collection is backed by the map, so changes to the map are + * reflected in the collection, and vice-versa. If the map is + * modified while an iteration over the collection is in progress + * (except through the iterator's own {@code remove} operation), + * the results of the iteration are undefined. The collection + * supports element removal, which removes the corresponding + * mapping from the map, via the {@code Iterator.remove}, + * {@code Collection.remove}, {@code removeAll}, + * {@code retainAll} and {@code clear} operations. It does not + * support the {@code add} or {@code addAll} operations. + */ + public Collection values() { + Collection vs = values; + return (vs != null) ? vs : (values = new Values()); + } + + /** + * Returns a {@link Set} view of the mappings contained in this map. + * The set's iterator returns the entries in ascending key order. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. If the map is modified + * while an iteration over the set is in progress (except through + * the iterator's own {@code remove} operation, or through the + * {@code setValue} operation on a map entry returned by the + * iterator) the results of the iteration are undefined. The set + * supports element removal, which removes the corresponding + * mapping from the map, via the {@code Iterator.remove}, + * {@code Set.remove}, {@code removeAll}, {@code retainAll} and + * {@code clear} operations. It does not support the + * {@code add} or {@code addAll} operations. + */ + public Set> entrySet() { + EntrySet es = entrySet; + return (es != null) ? es : (entrySet = new EntrySet()); + } + + /** + * @since 1.6 + */ + public NavigableMap7 descendingMap() { + NavigableMap7 km = descendingMap; + return (km != null) ? km : + (descendingMap = new DescendingSubMap(this, + true, null, true, + true, null, true)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromKey} or {@code toKey} is + * null and this map uses natural ordering, or its comparator + * does not permit null keys + * @throws IllegalArgumentException {@inheritDoc} + * @since 1.6 + */ + public NavigableMap7 subMap(K fromKey, boolean fromInclusive, + K toKey, boolean toInclusive) { + return new AscendingSubMap(this, + false, fromKey, fromInclusive, + false, toKey, toInclusive); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code toKey} is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @throws IllegalArgumentException {@inheritDoc} + * @since 1.6 + */ + public NavigableMap7 headMap(K toKey, boolean inclusive) { + return new AscendingSubMap(this, + true, null, true, + false, toKey, inclusive); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromKey} is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @throws IllegalArgumentException {@inheritDoc} + * @since 1.6 + */ + public NavigableMap7 tailMap(K fromKey, boolean inclusive) { + return new AscendingSubMap(this, + false, fromKey, inclusive, + true, null, true); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromKey} or {@code toKey} is + * null and this map uses natural ordering, or its comparator + * does not permit null keys + * @throws IllegalArgumentException {@inheritDoc} + */ + public SortedMap subMap(K fromKey, K toKey) { + return subMap(fromKey, true, toKey, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code toKey} is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @throws IllegalArgumentException {@inheritDoc} + */ + public SortedMap headMap(K toKey) { + return headMap(toKey, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromKey} is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @throws IllegalArgumentException {@inheritDoc} + */ + public SortedMap tailMap(K fromKey) { + return tailMap(fromKey, true); + } + + // View class support + + class Values extends AbstractCollection { + public Iterator iterator() { + return new ValueIterator(getFirstEntry()); + } + + public int size() { + return TreeMap7.this.size(); + } + + public boolean contains(Object o) { + return TreeMap7.this.containsValue(o); + } + + public boolean remove(Object o) { + for (Entry e = getFirstEntry(); e != null; e = successor(e)) { + if (valEquals(e.getValue(), o)) { + deleteEntry(e); + return true; + } + } + return false; + } + + public void clear() { + TreeMap7.this.clear(); + } + } + + class EntrySet extends AbstractSet> { + public Iterator> iterator() { + return new EntryIterator(getFirstEntry()); + } + + public boolean contains(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry entry = (Map.Entry) o; + V value = entry.getValue(); + Entry p = getEntry(entry.getKey()); + return p != null && valEquals(p.getValue(), value); + } + + public boolean remove(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry entry = (Map.Entry) o; + V value = entry.getValue(); + Entry p = getEntry(entry.getKey()); + if (p != null && valEquals(p.getValue(), value)) { + deleteEntry(p); + return true; + } + return false; + } + + public int size() { + return TreeMap7.this.size(); + } + + public void clear() { + TreeMap7.this.clear(); + } + } + + /* + * Unlike Values and EntrySet, the KeySet class is static, + * delegating to a NavigableMap7 to allow use by SubMaps, which + * outweighs the ugliness of needing type-tests for the following + * Iterator methods that are defined appropriately in main versus + * submap classes. + */ + + Iterator keyIterator() { + return new KeyIterator(getFirstEntry()); + } + + Iterator descendingKeyIterator() { + return new DescendingKeyIterator(getLastEntry()); + } + + static final class KeySet extends AbstractSet implements NavigableSet7 { + private final NavigableMap7 m; + KeySet(NavigableMap7 map) { m = map; } + + public Iterator iterator() { + if (m instanceof TreeMap7) + return ((TreeMap7)m).keyIterator(); + else + return (Iterator)(((TreeMap7.NavigableSubMap)m).keyIterator()); + } + + public Iterator descendingIterator() { + if (m instanceof TreeMap7) + return ((TreeMap7)m).descendingKeyIterator(); + else + return (Iterator)(((TreeMap7.NavigableSubMap)m).descendingKeyIterator()); + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean contains(Object o) { return m.containsKey(o); } + public void clear() { m.clear(); } + public E lower(E e) { return m.lowerKey(e); } + public E floor(E e) { return m.floorKey(e); } + public E ceiling(E e) { return m.ceilingKey(e); } + public E higher(E e) { return m.higherKey(e); } + public E first() { return m.firstKey(); } + public E last() { return m.lastKey(); } + public Comparator comparator() { return m.comparator(); } + public E pollFirst() { + Map.Entry e = m.pollFirstEntry(); + return (e == null) ? null : e.getKey(); + } + public E pollLast() { + Map.Entry e = m.pollLastEntry(); + return (e == null) ? null : e.getKey(); + } + public boolean remove(Object o) { + int oldSize = size(); + m.remove(o); + return size() != oldSize; + } + public NavigableSet7 subSet(E fromElement, boolean fromInclusive, + E toElement, boolean toInclusive) { + return new KeySet(m.subMap(fromElement, fromInclusive, + toElement, toInclusive)); + } + public NavigableSet7 headSet(E toElement, boolean inclusive) { + return new KeySet(m.headMap(toElement, inclusive)); + } + public NavigableSet7 tailSet(E fromElement, boolean inclusive) { + return new KeySet(m.tailMap(fromElement, inclusive)); + } + public SortedSet subSet(E fromElement, E toElement) { + return subSet(fromElement, true, toElement, false); + } + public SortedSet headSet(E toElement) { + return headSet(toElement, false); + } + public SortedSet tailSet(E fromElement) { + return tailSet(fromElement, true); + } + public NavigableSet7 descendingSet() { + return new KeySet(m.descendingMap()); + } + } + + /** + * Base class for TreeMap7 Iterators + */ + abstract class PrivateEntryIterator implements Iterator { + Entry next; + Entry lastReturned; + int expectedModCount; + + PrivateEntryIterator(Entry first) { + expectedModCount = modCount; + lastReturned = null; + next = first; + } + + public final boolean hasNext() { + return next != null; + } + + final Entry nextEntry() { + Entry e = next; + if (e == null) + throw new NoSuchElementException(); + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + next = successor(e); + lastReturned = e; + return e; + } + + final Entry prevEntry() { + Entry e = next; + if (e == null) + throw new NoSuchElementException(); + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + next = predecessor(e); + lastReturned = e; + return e; + } + + public void remove() { + if (lastReturned == null) + throw new IllegalStateException(); + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + // deleted entries are replaced by their successors + if (lastReturned.left != null && lastReturned.right != null) + next = lastReturned; + deleteEntry(lastReturned); + expectedModCount = modCount; + lastReturned = null; + } + } + + final class EntryIterator extends PrivateEntryIterator> { + EntryIterator(Entry first) { + super(first); + } + public Map.Entry next() { + return nextEntry(); + } + } + + final class ValueIterator extends PrivateEntryIterator { + ValueIterator(Entry first) { + super(first); + } + public V next() { + return nextEntry().value; + } + } + + final class KeyIterator extends PrivateEntryIterator { + KeyIterator(Entry first) { + super(first); + } + public K next() { + return nextEntry().key; + } + } + + final class DescendingKeyIterator extends PrivateEntryIterator { + DescendingKeyIterator(Entry first) { + super(first); + } + public K next() { + return prevEntry().key; + } + } + + // Little utilities + + /** + * Compares two keys using the correct comparison method for this TreeMap7. + */ + final int compare(Object k1, Object k2) { + return comparator==null ? ((Comparable)k1).compareTo((K)k2) + : comparator.compare((K)k1, (K)k2); + } + + /** + * Test two values for equality. Differs from o1.equals(o2) only in + * that it copes with {@code null} o1 properly. + */ + static final boolean valEquals(Object o1, Object o2) { + return (o1==null ? o2==null : o1.equals(o2)); + } + + /** + * Return SimpleImmutableEntry for entry, or null if null + */ + static Map.Entry exportEntry(TreeMap7.Entry e) { + return (e == null) ? null : + new AbstractMap7.SimpleImmutableEntry(e); + } + + /** + * Return key for entry, or null if null + */ + static K keyOrNull(TreeMap7.Entry e) { + return (e == null) ? null : e.key; + } + + /** + * Returns the key corresponding to the specified Entry. + * @throws NoSuchElementException if the Entry is null + */ + static K key(Entry e) { + if (e==null) + throw new NoSuchElementException(); + return e.key; + } + + + // SubMaps + + /** + * Dummy value serving as unmatchable fence key for unbounded + * SubMapIterators + */ + private static final Object UNBOUNDED = new Object(); + + /** + * @serial include + */ + abstract static class NavigableSubMap extends AbstractMap7 + implements NavigableMap7, java.io.Serializable { + /** + * The backing map. + */ + final TreeMap7 m; + + /** + * Endpoints are represented as triples (fromStart, lo, + * loInclusive) and (toEnd, hi, hiInclusive). If fromStart is + * true, then the low (absolute) bound is the start of the + * backing map, and the other values are ignored. Otherwise, + * if loInclusive is true, lo is the inclusive bound, else lo + * is the exclusive bound. Similarly for the upper bound. + */ + final K lo, hi; + final boolean fromStart, toEnd; + final boolean loInclusive, hiInclusive; + + NavigableSubMap(TreeMap7 m, + boolean fromStart, K lo, boolean loInclusive, + boolean toEnd, K hi, boolean hiInclusive) { + if (!fromStart && !toEnd) { + if (m.compare(lo, hi) > 0) + throw new IllegalArgumentException("fromKey > toKey"); + } else { + if (!fromStart) // type check + m.compare(lo, lo); + if (!toEnd) + m.compare(hi, hi); + } + + this.m = m; + this.fromStart = fromStart; + this.lo = lo; + this.loInclusive = loInclusive; + this.toEnd = toEnd; + this.hi = hi; + this.hiInclusive = hiInclusive; + } + + // internal utilities + + final boolean tooLow(Object key) { + if (!fromStart) { + int c = m.compare(key, lo); + if (c < 0 || (c == 0 && !loInclusive)) + return true; + } + return false; + } + + final boolean tooHigh(Object key) { + if (!toEnd) { + int c = m.compare(key, hi); + if (c > 0 || (c == 0 && !hiInclusive)) + return true; + } + return false; + } + + final boolean inRange(Object key) { + return !tooLow(key) && !tooHigh(key); + } + + final boolean inClosedRange(Object key) { + return (fromStart || m.compare(key, lo) >= 0) + && (toEnd || m.compare(hi, key) >= 0); + } + + final boolean inRange(Object key, boolean inclusive) { + return inclusive ? inRange(key) : inClosedRange(key); + } + + /* + * Absolute versions of relation operations. + * Subclasses map to these using like-named "sub" + * versions that invert senses for descending maps + */ + + final TreeMap7.Entry absLowest() { + TreeMap7.Entry e = + (fromStart ? m.getFirstEntry() : + (loInclusive ? m.getCeilingEntry(lo) : + m.getHigherEntry(lo))); + return (e == null || tooHigh(e.key)) ? null : e; + } + + final TreeMap7.Entry absHighest() { + TreeMap7.Entry e = + (toEnd ? m.getLastEntry() : + (hiInclusive ? m.getFloorEntry(hi) : + m.getLowerEntry(hi))); + return (e == null || tooLow(e.key)) ? null : e; + } + + final TreeMap7.Entry absCeiling(K key) { + if (tooLow(key)) + return absLowest(); + TreeMap7.Entry e = m.getCeilingEntry(key); + return (e == null || tooHigh(e.key)) ? null : e; + } + + final TreeMap7.Entry absHigher(K key) { + if (tooLow(key)) + return absLowest(); + TreeMap7.Entry e = m.getHigherEntry(key); + return (e == null || tooHigh(e.key)) ? null : e; + } + + final TreeMap7.Entry absFloor(K key) { + if (tooHigh(key)) + return absHighest(); + TreeMap7.Entry e = m.getFloorEntry(key); + return (e == null || tooLow(e.key)) ? null : e; + } + + final TreeMap7.Entry absLower(K key) { + if (tooHigh(key)) + return absHighest(); + TreeMap7.Entry e = m.getLowerEntry(key); + return (e == null || tooLow(e.key)) ? null : e; + } + + /** Returns the absolute high fence for ascending traversal */ + final TreeMap7.Entry absHighFence() { + return (toEnd ? null : (hiInclusive ? + m.getHigherEntry(hi) : + m.getCeilingEntry(hi))); + } + + /** Return the absolute low fence for descending traversal */ + final TreeMap7.Entry absLowFence() { + return (fromStart ? null : (loInclusive ? + m.getLowerEntry(lo) : + m.getFloorEntry(lo))); + } + + // Abstract methods defined in ascending vs descending classes + // These relay to the appropriate absolute versions + + abstract TreeMap7.Entry subLowest(); + abstract TreeMap7.Entry subHighest(); + abstract TreeMap7.Entry subCeiling(K key); + abstract TreeMap7.Entry subHigher(K key); + abstract TreeMap7.Entry subFloor(K key); + abstract TreeMap7.Entry subLower(K key); + + /** Returns ascending iterator from the perspective of this submap */ + abstract Iterator keyIterator(); + + /** Returns descending iterator from the perspective of this submap */ + abstract Iterator descendingKeyIterator(); + + // public methods + + public boolean isEmpty() { + return (fromStart && toEnd) ? m.isEmpty() : entrySet().isEmpty(); + } + + public int size() { + return (fromStart && toEnd) ? m.size() : entrySet().size(); + } + + public final boolean containsKey(Object key) { + return inRange(key) && m.containsKey(key); + } + + public final V put(K key, V value) { + if (!inRange(key)) + throw new IllegalArgumentException("key out of range"); + return m.put(key, value); + } + + public final V get(Object key) { + return !inRange(key) ? null : m.get(key); + } + + public final V remove(Object key) { + return !inRange(key) ? null : m.remove(key); + } + + public final Map.Entry ceilingEntry(K key) { + return exportEntry(subCeiling(key)); + } + + public final K ceilingKey(K key) { + return keyOrNull(subCeiling(key)); + } + + public final Map.Entry higherEntry(K key) { + return exportEntry(subHigher(key)); + } + + public final K higherKey(K key) { + return keyOrNull(subHigher(key)); + } + + public final Map.Entry floorEntry(K key) { + return exportEntry(subFloor(key)); + } + + public final K floorKey(K key) { + return keyOrNull(subFloor(key)); + } + + public final Map.Entry lowerEntry(K key) { + return exportEntry(subLower(key)); + } + + public final K lowerKey(K key) { + return keyOrNull(subLower(key)); + } + + public final K firstKey() { + return key(subLowest()); + } + + public final K lastKey() { + return key(subHighest()); + } + + public final Map.Entry firstEntry() { + return exportEntry(subLowest()); + } + + public final Map.Entry lastEntry() { + return exportEntry(subHighest()); + } + + public final Map.Entry pollFirstEntry() { + TreeMap7.Entry e = subLowest(); + Map.Entry result = exportEntry(e); + if (e != null) + m.deleteEntry(e); + return result; + } + + public final Map.Entry pollLastEntry() { + TreeMap7.Entry e = subHighest(); + Map.Entry result = exportEntry(e); + if (e != null) + m.deleteEntry(e); + return result; + } + + // Views + transient NavigableMap7 descendingMapView = null; + transient EntrySetView entrySetView = null; + transient KeySet navigableKeySetView = null; + + public final NavigableSet7 navigableKeySet() { + KeySet nksv = navigableKeySetView; + return (nksv != null) ? nksv : + (navigableKeySetView = new TreeMap7.KeySet(this)); + } + + public final Set keySet() { + return navigableKeySet(); + } + + public NavigableSet7 descendingKeySet() { + return descendingMap().navigableKeySet(); + } + + public final SortedMap subMap(K fromKey, K toKey) { + return subMap(fromKey, true, toKey, false); + } + + public final SortedMap headMap(K toKey) { + return headMap(toKey, false); + } + + public final SortedMap tailMap(K fromKey) { + return tailMap(fromKey, true); + } + + // View classes + + abstract class EntrySetView extends AbstractSet> { + private transient int size = -1, sizeModCount; + + public int size() { + if (fromStart && toEnd) + return m.size(); + if (size == -1 || sizeModCount != m.modCount) { + sizeModCount = m.modCount; + size = 0; + Iterator i = iterator(); + while (i.hasNext()) { + size++; + i.next(); + } + } + return size; + } + + public boolean isEmpty() { + TreeMap7.Entry n = absLowest(); + return n == null || tooHigh(n.key); + } + + public boolean contains(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry entry = (Map.Entry) o; + K key = entry.getKey(); + if (!inRange(key)) + return false; + TreeMap7.Entry node = m.getEntry(key); + return node != null && + valEquals(node.getValue(), entry.getValue()); + } + + public boolean remove(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry entry = (Map.Entry) o; + K key = entry.getKey(); + if (!inRange(key)) + return false; + TreeMap7.Entry node = m.getEntry(key); + if (node!=null && valEquals(node.getValue(), + entry.getValue())) { + m.deleteEntry(node); + return true; + } + return false; + } + } + + /** + * Iterators for SubMaps + */ + abstract class SubMapIterator implements Iterator { + TreeMap7.Entry lastReturned; + TreeMap7.Entry next; + final Object fenceKey; + int expectedModCount; + + SubMapIterator(TreeMap7.Entry first, + TreeMap7.Entry fence) { + expectedModCount = m.modCount; + lastReturned = null; + next = first; + fenceKey = fence == null ? UNBOUNDED : fence.key; + } + + public final boolean hasNext() { + return next != null && next.key != fenceKey; + } + + final TreeMap7.Entry nextEntry() { + TreeMap7.Entry e = next; + if (e == null || e.key == fenceKey) + throw new NoSuchElementException(); + if (m.modCount != expectedModCount) + throw new ConcurrentModificationException(); + next = successor(e); + lastReturned = e; + return e; + } + + final TreeMap7.Entry prevEntry() { + TreeMap7.Entry e = next; + if (e == null || e.key == fenceKey) + throw new NoSuchElementException(); + if (m.modCount != expectedModCount) + throw new ConcurrentModificationException(); + next = predecessor(e); + lastReturned = e; + return e; + } + + final void removeAscending() { + if (lastReturned == null) + throw new IllegalStateException(); + if (m.modCount != expectedModCount) + throw new ConcurrentModificationException(); + // deleted entries are replaced by their successors + if (lastReturned.left != null && lastReturned.right != null) + next = lastReturned; + m.deleteEntry(lastReturned); + lastReturned = null; + expectedModCount = m.modCount; + } + + final void removeDescending() { + if (lastReturned == null) + throw new IllegalStateException(); + if (m.modCount != expectedModCount) + throw new ConcurrentModificationException(); + m.deleteEntry(lastReturned); + lastReturned = null; + expectedModCount = m.modCount; + } + + } + + final class SubMapEntryIterator extends SubMapIterator> { + SubMapEntryIterator(TreeMap7.Entry first, + TreeMap7.Entry fence) { + super(first, fence); + } + public Map.Entry next() { + return nextEntry(); + } + public void remove() { + removeAscending(); + } + } + + final class SubMapKeyIterator extends SubMapIterator { + SubMapKeyIterator(TreeMap7.Entry first, + TreeMap7.Entry fence) { + super(first, fence); + } + public K next() { + return nextEntry().key; + } + public void remove() { + removeAscending(); + } + } + + final class DescendingSubMapEntryIterator extends SubMapIterator> { + DescendingSubMapEntryIterator(TreeMap7.Entry last, + TreeMap7.Entry fence) { + super(last, fence); + } + + public Map.Entry next() { + return prevEntry(); + } + public void remove() { + removeDescending(); + } + } + + final class DescendingSubMapKeyIterator extends SubMapIterator { + DescendingSubMapKeyIterator(TreeMap7.Entry last, + TreeMap7.Entry fence) { + super(last, fence); + } + public K next() { + return prevEntry().key; + } + public void remove() { + removeDescending(); + } + } + } + + /** + * @serial include + */ + static final class AscendingSubMap extends NavigableSubMap { + private static final long serialVersionUID = 912986545866124060L; + + AscendingSubMap(TreeMap7 m, + boolean fromStart, K lo, boolean loInclusive, + boolean toEnd, K hi, boolean hiInclusive) { + super(m, fromStart, lo, loInclusive, toEnd, hi, hiInclusive); + } + + public Comparator comparator() { + return m.comparator(); + } + + public NavigableMap7 subMap(K fromKey, boolean fromInclusive, + K toKey, boolean toInclusive) { + if (!inRange(fromKey, fromInclusive)) + throw new IllegalArgumentException("fromKey out of range"); + if (!inRange(toKey, toInclusive)) + throw new IllegalArgumentException("toKey out of range"); + return new AscendingSubMap(m, + false, fromKey, fromInclusive, + false, toKey, toInclusive); + } + + public NavigableMap7 headMap(K toKey, boolean inclusive) { + if (!inRange(toKey, inclusive)) + throw new IllegalArgumentException("toKey out of range"); + return new AscendingSubMap(m, + fromStart, lo, loInclusive, + false, toKey, inclusive); + } + + public NavigableMap7 tailMap(K fromKey, boolean inclusive) { + if (!inRange(fromKey, inclusive)) + throw new IllegalArgumentException("fromKey out of range"); + return new AscendingSubMap(m, + false, fromKey, inclusive, + toEnd, hi, hiInclusive); + } + + public NavigableMap7 descendingMap() { + NavigableMap7 mv = descendingMapView; + return (mv != null) ? mv : + (descendingMapView = + new DescendingSubMap(m, + fromStart, lo, loInclusive, + toEnd, hi, hiInclusive)); + } + + Iterator keyIterator() { + return new SubMapKeyIterator(absLowest(), absHighFence()); + } + + Iterator descendingKeyIterator() { + return new DescendingSubMapKeyIterator(absHighest(), absLowFence()); + } + + final class AscendingEntrySetView extends EntrySetView { + public Iterator> iterator() { + return new SubMapEntryIterator(absLowest(), absHighFence()); + } + } + + public Set> entrySet() { + EntrySetView es = entrySetView; + return (es != null) ? es : new AscendingEntrySetView(); + } + + TreeMap7.Entry subLowest() { return absLowest(); } + TreeMap7.Entry subHighest() { return absHighest(); } + TreeMap7.Entry subCeiling(K key) { return absCeiling(key); } + TreeMap7.Entry subHigher(K key) { return absHigher(key); } + TreeMap7.Entry subFloor(K key) { return absFloor(key); } + TreeMap7.Entry subLower(K key) { return absLower(key); } + } + + /** + * @serial include + */ + static final class DescendingSubMap extends NavigableSubMap { + private static final long serialVersionUID = 912986545866120460L; + DescendingSubMap(TreeMap7 m, + boolean fromStart, K lo, boolean loInclusive, + boolean toEnd, K hi, boolean hiInclusive) { + super(m, fromStart, lo, loInclusive, toEnd, hi, hiInclusive); + } + + private final Comparator reverseComparator = + Collections.reverseOrder(m.comparator); + + public Comparator comparator() { + return reverseComparator; + } + + public NavigableMap7 subMap(K fromKey, boolean fromInclusive, + K toKey, boolean toInclusive) { + if (!inRange(fromKey, fromInclusive)) + throw new IllegalArgumentException("fromKey out of range"); + if (!inRange(toKey, toInclusive)) + throw new IllegalArgumentException("toKey out of range"); + return new DescendingSubMap(m, + false, toKey, toInclusive, + false, fromKey, fromInclusive); + } + + public NavigableMap7 headMap(K toKey, boolean inclusive) { + if (!inRange(toKey, inclusive)) + throw new IllegalArgumentException("toKey out of range"); + return new DescendingSubMap(m, + false, toKey, inclusive, + toEnd, hi, hiInclusive); + } + + public NavigableMap7 tailMap(K fromKey, boolean inclusive) { + if (!inRange(fromKey, inclusive)) + throw new IllegalArgumentException("fromKey out of range"); + return new DescendingSubMap(m, + fromStart, lo, loInclusive, + false, fromKey, inclusive); + } + + public NavigableMap7 descendingMap() { + NavigableMap7 mv = descendingMapView; + return (mv != null) ? mv : + (descendingMapView = + new AscendingSubMap(m, + fromStart, lo, loInclusive, + toEnd, hi, hiInclusive)); + } + + Iterator keyIterator() { + return new DescendingSubMapKeyIterator(absHighest(), absLowFence()); + } + + Iterator descendingKeyIterator() { + return new SubMapKeyIterator(absLowest(), absHighFence()); + } + + final class DescendingEntrySetView extends EntrySetView { + public Iterator> iterator() { + return new DescendingSubMapEntryIterator(absHighest(), absLowFence()); + } + } + + public Set> entrySet() { + EntrySetView es = entrySetView; + return (es != null) ? es : new DescendingEntrySetView(); + } + + TreeMap7.Entry subLowest() { return absHighest(); } + TreeMap7.Entry subHighest() { return absLowest(); } + TreeMap7.Entry subCeiling(K key) { return absFloor(key); } + TreeMap7.Entry subHigher(K key) { return absLower(key); } + TreeMap7.Entry subFloor(K key) { return absCeiling(key); } + TreeMap7.Entry subLower(K key) { return absHigher(key); } + } + + /** + * This class exists solely for the sake of serialization + * compatibility with previous releases of TreeMap7 that did not + * support NavigableMap7. It translates an old-version SubMap into + * a new-version AscendingSubMap. This class is never otherwise + * used. + * + * @serial include + */ + private class SubMap extends AbstractMap7 + implements SortedMap, java.io.Serializable { + private static final long serialVersionUID = -6520786458950516097L; + private boolean fromStart = false, toEnd = false; + private K fromKey, toKey; + private Object readResolve() { + return new AscendingSubMap(TreeMap7.this, + fromStart, fromKey, true, + toEnd, toKey, false); + } + public Set> entrySet() { throw new InternalError(); } + public K lastKey() { throw new InternalError(); } + public K firstKey() { throw new InternalError(); } + public SortedMap subMap(K fromKey, K toKey) { throw new InternalError(); } + public SortedMap headMap(K toKey) { throw new InternalError(); } + public SortedMap tailMap(K fromKey) { throw new InternalError(); } + public Comparator comparator() { throw new InternalError(); } + } + + + // Red-black mechanics + + private static final boolean RED = false; + private static final boolean BLACK = true; + + /** + * Node in the Tree. Doubles as a means to pass key-value pairs back to + * user (see Map.Entry). + */ + + static final class Entry implements Map.Entry { + K key; + V value; + Entry left = null; + Entry right = null; + Entry parent; + boolean color = BLACK; + + /** + * Make a new cell with given key, value, and parent, and with + * {@code null} child links, and BLACK color. + */ + Entry(K key, V value, Entry parent) { + this.key = key; + this.value = value; + this.parent = parent; + } + + /** + * Returns the key. + * + * @return the key + */ + public K getKey() { + return key; + } + + /** + * Returns the value associated with the key. + * + * @return the value associated with the key + */ + public V getValue() { + return value; + } + + /** + * Replaces the value currently associated with the key with the given + * value. + * + * @return the value associated with the key before this method was + * called + */ + public V setValue(V value) { + V oldValue = this.value; + this.value = value; + return oldValue; + } + + public boolean equals(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry e = (Map.Entry)o; + + return valEquals(key,e.getKey()) && valEquals(value,e.getValue()); + } + + public int hashCode() { + int keyHash = (key==null ? 0 : key.hashCode()); + int valueHash = (value==null ? 0 : value.hashCode()); + return keyHash ^ valueHash; + } + + public String toString() { + return key + "=" + value; + } + } + + /** + * Returns the first Entry in the TreeMap7 (according to the TreeMap7's + * key-sort function). Returns null if the TreeMap7 is empty. + */ + final Entry getFirstEntry() { + Entry p = root; + if (p != null) + while (p.left != null) + p = p.left; + return p; + } + + /** + * Returns the last Entry in the TreeMap7 (according to the TreeMap7's + * key-sort function). Returns null if the TreeMap7 is empty. + */ + final Entry getLastEntry() { + Entry p = root; + if (p != null) + while (p.right != null) + p = p.right; + return p; + } + + /** + * Returns the successor of the specified Entry, or null if no such. + */ + static TreeMap7.Entry successor(Entry t) { + if (t == null) + return null; + else if (t.right != null) { + Entry p = t.right; + while (p.left != null) + p = p.left; + return p; + } else { + Entry p = t.parent; + Entry ch = t; + while (p != null && ch == p.right) { + ch = p; + p = p.parent; + } + return p; + } + } + + /** + * Returns the predecessor of the specified Entry, or null if no such. + */ + static Entry predecessor(Entry t) { + if (t == null) + return null; + else if (t.left != null) { + Entry p = t.left; + while (p.right != null) + p = p.right; + return p; + } else { + Entry p = t.parent; + Entry ch = t; + while (p != null && ch == p.left) { + ch = p; + p = p.parent; + } + return p; + } + } + + /** + * Balancing operations. + * + * Implementations of rebalancings during insertion and deletion are + * slightly different than the CLR version. Rather than using dummy + * nilnodes, we use a set of accessors that deal properly with null. They + * are used to avoid messiness surrounding nullness checks in the main + * algorithms. + */ + + private static boolean colorOf(Entry p) { + return (p == null ? BLACK : p.color); + } + + private static Entry parentOf(Entry p) { + return (p == null ? null: p.parent); + } + + private static void setColor(Entry p, boolean c) { + if (p != null) + p.color = c; + } + + private static Entry leftOf(Entry p) { + return (p == null) ? null: p.left; + } + + private static Entry rightOf(Entry p) { + return (p == null) ? null: p.right; + } + + /** From CLR */ + private void rotateLeft(Entry p) { + if (p != null) { + Entry r = p.right; + p.right = r.left; + if (r.left != null) + r.left.parent = p; + r.parent = p.parent; + if (p.parent == null) + root = r; + else if (p.parent.left == p) + p.parent.left = r; + else + p.parent.right = r; + r.left = p; + p.parent = r; + } + } + + /** From CLR */ + private void rotateRight(Entry p) { + if (p != null) { + Entry l = p.left; + p.left = l.right; + if (l.right != null) l.right.parent = p; + l.parent = p.parent; + if (p.parent == null) + root = l; + else if (p.parent.right == p) + p.parent.right = l; + else p.parent.left = l; + l.right = p; + p.parent = l; + } + } + + /** From CLR */ + private void fixAfterInsertion(Entry x) { + x.color = RED; + + while (x != null && x != root && x.parent.color == RED) { + if (parentOf(x) == leftOf(parentOf(parentOf(x)))) { + Entry y = rightOf(parentOf(parentOf(x))); + if (colorOf(y) == RED) { + setColor(parentOf(x), BLACK); + setColor(y, BLACK); + setColor(parentOf(parentOf(x)), RED); + x = parentOf(parentOf(x)); + } else { + if (x == rightOf(parentOf(x))) { + x = parentOf(x); + rotateLeft(x); + } + setColor(parentOf(x), BLACK); + setColor(parentOf(parentOf(x)), RED); + rotateRight(parentOf(parentOf(x))); + } + } else { + Entry y = leftOf(parentOf(parentOf(x))); + if (colorOf(y) == RED) { + setColor(parentOf(x), BLACK); + setColor(y, BLACK); + setColor(parentOf(parentOf(x)), RED); + x = parentOf(parentOf(x)); + } else { + if (x == leftOf(parentOf(x))) { + x = parentOf(x); + rotateRight(x); + } + setColor(parentOf(x), BLACK); + setColor(parentOf(parentOf(x)), RED); + rotateLeft(parentOf(parentOf(x))); + } + } + } + root.color = BLACK; + } + + /** + * Delete node p, and then rebalance the tree. + */ + private void deleteEntry(Entry p) { + modCount++; + size--; + + // If strictly internal, copy successor's element to p and then make p + // point to successor. + if (p.left != null && p.right != null) { + Entry s = successor(p); + p.key = s.key; + p.value = s.value; + p = s; + } // p has 2 children + + // Start fixup at replacement node, if it exists. + Entry replacement = (p.left != null ? p.left : p.right); + + if (replacement != null) { + // Link replacement to parent + replacement.parent = p.parent; + if (p.parent == null) + root = replacement; + else if (p == p.parent.left) + p.parent.left = replacement; + else + p.parent.right = replacement; + + // Null out links so they are OK to use by fixAfterDeletion. + p.left = p.right = p.parent = null; + + // Fix replacement + if (p.color == BLACK) + fixAfterDeletion(replacement); + } else if (p.parent == null) { // return if we are the only node. + root = null; + } else { // No children. Use self as phantom replacement and unlink. + if (p.color == BLACK) + fixAfterDeletion(p); + + if (p.parent != null) { + if (p == p.parent.left) + p.parent.left = null; + else if (p == p.parent.right) + p.parent.right = null; + p.parent = null; + } + } + } + + /** From CLR */ + private void fixAfterDeletion(Entry x) { + while (x != root && colorOf(x) == BLACK) { + if (x == leftOf(parentOf(x))) { + Entry sib = rightOf(parentOf(x)); + + if (colorOf(sib) == RED) { + setColor(sib, BLACK); + setColor(parentOf(x), RED); + rotateLeft(parentOf(x)); + sib = rightOf(parentOf(x)); + } + + if (colorOf(leftOf(sib)) == BLACK && + colorOf(rightOf(sib)) == BLACK) { + setColor(sib, RED); + x = parentOf(x); + } else { + if (colorOf(rightOf(sib)) == BLACK) { + setColor(leftOf(sib), BLACK); + setColor(sib, RED); + rotateRight(sib); + sib = rightOf(parentOf(x)); + } + setColor(sib, colorOf(parentOf(x))); + setColor(parentOf(x), BLACK); + setColor(rightOf(sib), BLACK); + rotateLeft(parentOf(x)); + x = root; + } + } else { // symmetric + Entry sib = leftOf(parentOf(x)); + + if (colorOf(sib) == RED) { + setColor(sib, BLACK); + setColor(parentOf(x), RED); + rotateRight(parentOf(x)); + sib = leftOf(parentOf(x)); + } + + if (colorOf(rightOf(sib)) == BLACK && + colorOf(leftOf(sib)) == BLACK) { + setColor(sib, RED); + x = parentOf(x); + } else { + if (colorOf(leftOf(sib)) == BLACK) { + setColor(rightOf(sib), BLACK); + setColor(sib, RED); + rotateLeft(sib); + sib = leftOf(parentOf(x)); + } + setColor(sib, colorOf(parentOf(x))); + setColor(parentOf(x), BLACK); + setColor(leftOf(sib), BLACK); + rotateRight(parentOf(x)); + x = root; + } + } + } + + setColor(x, BLACK); + } + + private static final long serialVersionUID = 919286545866124006L; + + /** + * Save the state of the {@code TreeMap7} instance to a stream (i.e., + * serialize it). + * + * @serialData The size of the TreeMap7 (the number of key-value + * mappings) is emitted (int), followed by the key (Object) + * and value (Object) for each key-value mapping represented + * by the TreeMap7. The key-value mappings are emitted in + * key-order (as determined by the TreeMap7's Comparator, + * or by the keys' natural ordering if the TreeMap7 has no + * Comparator). + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + // Write out the Comparator and any hidden stuff + s.defaultWriteObject(); + + // Write out size (number of Mappings) + s.writeInt(size); + + // Write out keys and values (alternating) + for (Iterator> i = entrySet().iterator(); i.hasNext(); ) { + Map.Entry e = i.next(); + s.writeObject(e.getKey()); + s.writeObject(e.getValue()); + } + } + + /** + * Reconstitute the {@code TreeMap7} instance from a stream (i.e., + * deserialize it). + */ + private void readObject(final java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + // Read in the Comparator and any hidden stuff + s.defaultReadObject(); + + // Read in size + int size = s.readInt(); + + buildFromSorted(size, null, s, null); + } + + /** Intended to be called only from TreeSet.readObject */ + void readTreeSet(int size, java.io.ObjectInputStream s, V defaultVal) + throws java.io.IOException, ClassNotFoundException { + buildFromSorted(size, null, s, defaultVal); + } + + /** Intended to be called only from TreeSet.addAll */ + void addAllForTreeSet(SortedSet set, V defaultVal) { + try { + buildFromSorted(set.size(), set.iterator(), null, defaultVal); + } catch (java.io.IOException cannotHappen) { + } catch (ClassNotFoundException cannotHappen) { + } + } + + + /** + * Linear time tree building algorithm from sorted data. Can accept keys + * and/or values from iterator or stream. This leads to too many + * parameters, but seems better than alternatives. The four formats + * that this method accepts are: + * + * 1) An iterator of Map.Entries. (it != null, defaultVal == null). + * 2) An iterator of keys. (it != null, defaultVal != null). + * 3) A stream of alternating serialized keys and values. + * (it == null, defaultVal == null). + * 4) A stream of serialized keys. (it == null, defaultVal != null). + * + * It is assumed that the comparator of the TreeMap7 is already set prior + * to calling this method. + * + * @param size the number of keys (or key-value pairs) to be read from + * the iterator or stream + * @param it If non-null, new entries are created from entries + * or keys read from this iterator. + * @param str If non-null, new entries are created from keys and + * possibly values read from this stream in serialized form. + * Exactly one of it and str should be non-null. + * @param defaultVal if non-null, this default value is used for + * each value in the map. If null, each value is read from + * iterator or stream, as described above. + * @throws IOException propagated from stream reads. This cannot + * occur if str is null. + * @throws ClassNotFoundException propagated from readObject. + * This cannot occur if str is null. + */ + private void buildFromSorted(int size, Iterator it, + java.io.ObjectInputStream str, + V defaultVal) + throws java.io.IOException, ClassNotFoundException { + this.size = size; + root = buildFromSorted(0, 0, size-1, computeRedLevel(size), + it, str, defaultVal); + } + + /** + * Recursive "helper method" that does the real work of the + * previous method. Identically named parameters have + * identical definitions. Additional parameters are documented below. + * It is assumed that the comparator and size fields of the TreeMap7 are + * already set prior to calling this method. (It ignores both fields.) + * + * @param level the current level of tree. Initial call should be 0. + * @param lo the first element index of this subtree. Initial should be 0. + * @param hi the last element index of this subtree. Initial should be + * size-1. + * @param redLevel the level at which nodes should be red. + * Must be equal to computeRedLevel for tree of this size. + */ + private final Entry buildFromSorted(int level, int lo, int hi, + int redLevel, + Iterator it, + java.io.ObjectInputStream str, + V defaultVal) + throws java.io.IOException, ClassNotFoundException { + /* + * Strategy: The root is the middlemost element. To get to it, we + * have to first recursively construct the entire left subtree, + * so as to grab all of its elements. We can then proceed with right + * subtree. + * + * The lo and hi arguments are the minimum and maximum + * indices to pull out of the iterator or stream for current subtree. + * They are not actually indexed, we just proceed sequentially, + * ensuring that items are extracted in corresponding order. + */ + + if (hi < lo) return null; + + int mid = (lo + hi) >>> 1; + + Entry left = null; + if (lo < mid) + left = buildFromSorted(level+1, lo, mid - 1, redLevel, + it, str, defaultVal); + + // extract key and/or value from iterator or stream + K key; + V value; + if (it != null) { + if (defaultVal==null) { + Map.Entry entry = (Map.Entry)it.next(); + key = entry.getKey(); + value = entry.getValue(); + } else { + key = (K)it.next(); + value = defaultVal; + } + } else { // use stream + key = (K) str.readObject(); + value = (defaultVal != null ? defaultVal : (V) str.readObject()); + } + + Entry middle = new Entry(key, value, null); + + // color nodes in non-full bottommost level red + if (level == redLevel) + middle.color = RED; + + if (left != null) { + middle.left = left; + left.parent = middle; + } + + if (mid < hi) { + Entry right = buildFromSorted(level+1, mid+1, hi, redLevel, + it, str, defaultVal); + middle.right = right; + right.parent = middle; + } + + return middle; + } + + /** + * Find the level down to which to assign all nodes BLACK. This is the + * last `full' level of the complete binary tree produced by + * buildTree. The remaining nodes are colored RED. (This makes a `nice' + * set of color assignments wrt future insertions.) This level number is + * computed by finding the number of splits needed to reach the zeroeth + * node. (The answer is ~lg(N), but in any case must be computed by same + * quick O(lg(N)) loop.) + */ + private static int computeRedLevel(int sz) { + int level = 0; + for (int m = sz - 1; m >= 0; m = m / 2 - 1) + level++; + return level; + } +} \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/util/java7_util/TreeSet7.java b/src/ooxml/java/org/apache/poi/util/java7_util/TreeSet7.java new file mode 100644 index 000000000..3369b9c1f --- /dev/null +++ b/src/ooxml/java/org/apache/poi/util/java7_util/TreeSet7.java @@ -0,0 +1,554 @@ +/* + * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.apache.poi.util.java7_util; + +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.ConcurrentModificationException; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeMap; + +/** + * A {@link NavigableSet7} implementation based on a {@link TreeMap}. + * The elements are ordered using their {@linkplain Comparable natural + * ordering}, or by a {@link Comparator} provided at set creation + * time, depending on which constructor is used. + * + *

This implementation provides guaranteed log(n) time cost for the basic + * operations ({@code add}, {@code remove} and {@code contains}). + * + *

Note that the ordering maintained by a set (whether or not an explicit + * comparator is provided) must be consistent with equals if it is to + * correctly implement the {@code Set} interface. (See {@code Comparable} + * or {@code Comparator} for a precise definition of consistent with + * equals.) This is so because the {@code Set} interface is defined in + * terms of the {@code equals} operation, but a {@code TreeSet7} instance + * performs all element comparisons using its {@code compareTo} (or + * {@code compare}) method, so two elements that are deemed equal by this method + * are, from the standpoint of the set, equal. The behavior of a set + * is well-defined even if its ordering is inconsistent with equals; it + * just fails to obey the general contract of the {@code Set} interface. + * + *

Note that this implementation is not synchronized. + * If multiple threads access a tree set concurrently, and at least one + * of the threads modifies the set, it must be synchronized + * externally. This is typically accomplished by synchronizing on some + * object that naturally encapsulates the set. + * If no such object exists, the set should be "wrapped" using the + * {@link Collections#synchronizedSortedSet Collections.synchronizedSortedSet} + * method. This is best done at creation time, to prevent accidental + * unsynchronized access to the set:

+ *   SortedSet s = Collections.synchronizedSortedSet(new TreeSet7(...));
+ * + *

The iterators returned by this class's {@code iterator} method are + * fail-fast: if the set is modified at any time after the iterator is + * created, in any way except through the iterator's own {@code remove} + * method, the iterator will throw a {@link ConcurrentModificationException}. + * Thus, in the face of concurrent modification, the iterator fails quickly + * and cleanly, rather than risking arbitrary, non-deterministic behavior at + * an undetermined time in the future. + * + *

Note that the fail-fast behavior of an iterator cannot be guaranteed + * as it is, generally speaking, impossible to make any hard guarantees in the + * presence of unsynchronized concurrent modification. Fail-fast iterators + * throw {@code ConcurrentModificationException} on a best-effort basis. + * Therefore, it would be wrong to write a program that depended on this + * exception for its correctness: the fail-fast behavior of iterators + * should be used only to detect bugs. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @param the type of elements maintained by this set + * + * @author Josh Bloch + * @see Collection + * @see Set + * @see HashSet + * @see Comparable + * @see Comparator + * @see TreeMap + * @since 1.2 + */ + +public class TreeSet7 extends AbstractSet7 + implements NavigableSet7, Cloneable, java.io.Serializable +{ + /** + * The backing map. + */ + private transient NavigableMap7 m; + + // Dummy value to associate with an Object in the backing Map + private static final Object PRESENT = new Object(); + + /** + * Constructs a set backed by the specified navigable map. + */ + TreeSet7(NavigableMap7 m) { + this.m = m; + } + + /** + * Constructs a new, empty tree set, sorted according to the + * natural ordering of its elements. All elements inserted into + * the set must implement the {@link Comparable} interface. + * Furthermore, all such elements must be mutually + * comparable: {@code e1.compareTo(e2)} must not throw a + * {@code ClassCastException} for any elements {@code e1} and + * {@code e2} in the set. If the user attempts to add an element + * to the set that violates this constraint (for example, the user + * attempts to add a string element to a set whose elements are + * integers), the {@code add} call will throw a + * {@code ClassCastException}. + */ + public TreeSet7() { + this(new TreeMap7()); + } + + /** + * Constructs a new, empty tree set, sorted according to the specified + * comparator. All elements inserted into the set must be mutually + * comparable by the specified comparator: {@code comparator.compare(e1, + * e2)} must not throw a {@code ClassCastException} for any elements + * {@code e1} and {@code e2} in the set. If the user attempts to add + * an element to the set that violates this constraint, the + * {@code add} call will throw a {@code ClassCastException}. + * + * @param comparator the comparator that will be used to order this set. + * If {@code null}, the {@linkplain Comparable natural + * ordering} of the elements will be used. + */ + public TreeSet7(Comparator comparator) { + this(new TreeMap7(comparator)); + } + + /** + * Constructs a new tree set containing the elements in the specified + * collection, sorted according to the natural ordering of its + * elements. All elements inserted into the set must implement the + * {@link Comparable} interface. Furthermore, all such elements must be + * mutually comparable: {@code e1.compareTo(e2)} must not throw a + * {@code ClassCastException} for any elements {@code e1} and + * {@code e2} in the set. + * + * @param c collection whose elements will comprise the new set + * @throws ClassCastException if the elements in {@code c} are + * not {@link Comparable}, or are not mutually comparable + * @throws NullPointerException if the specified collection is null + */ + public TreeSet7(Collection c) { + this(); + addAll(c); + } + + /** + * Constructs a new tree set containing the same elements and + * using the same ordering as the specified sorted set. + * + * @param s sorted set whose elements will comprise the new set + * @throws NullPointerException if the specified sorted set is null + */ + public TreeSet7(SortedSet s) { + this(s.comparator()); + addAll(s); + } + + /** + * Returns an iterator over the elements in this set in ascending order. + * + * @return an iterator over the elements in this set in ascending order + */ + public Iterator iterator() { + return m.navigableKeySet().iterator(); + } + + /** + * Returns an iterator over the elements in this set in descending order. + * + * @return an iterator over the elements in this set in descending order + * @since 1.6 + */ + public Iterator descendingIterator() { + return m.descendingKeySet().iterator(); + } + + /** + * @since 1.6 + */ + public NavigableSet7 descendingSet() { + return new TreeSet7(m.descendingMap()); + } + + /** + * Returns the number of elements in this set (its cardinality). + * + * @return the number of elements in this set (its cardinality) + */ + public int size() { + return m.size(); + } + + /** + * Returns {@code true} if this set contains no elements. + * + * @return {@code true} if this set contains no elements + */ + public boolean isEmpty() { + return m.isEmpty(); + } + + /** + * Returns {@code true} if this set contains the specified element. + * More formally, returns {@code true} if and only if this set + * contains an element {@code e} such that + * (o==null ? e==null : o.equals(e)). + * + * @param o object to be checked for containment in this set + * @return {@code true} if this set contains the specified element + * @throws ClassCastException if the specified object cannot be compared + * with the elements currently in the set + * @throws NullPointerException if the specified element is null + * and this set uses natural ordering, or its comparator + * does not permit null elements + */ + public boolean contains(Object o) { + return m.containsKey(o); + } + + /** + * Adds the specified element to this set if it is not already present. + * More formally, adds the specified element {@code e} to this set if + * the set contains no element {@code e2} such that + * (e==null ? e2==null : e.equals(e2)). + * If this set already contains the element, the call leaves the set + * unchanged and returns {@code false}. + * + * @param e element to be added to this set + * @return {@code true} if this set did not already contain the specified + * element + * @throws ClassCastException if the specified object cannot be compared + * with the elements currently in this set + * @throws NullPointerException if the specified element is null + * and this set uses natural ordering, or its comparator + * does not permit null elements + */ + public boolean add(E e) { + return m.put(e, PRESENT)==null; + } + + /** + * Removes the specified element from this set if it is present. + * More formally, removes an element {@code e} such that + * (o==null ? e==null : o.equals(e)), + * if this set contains such an element. Returns {@code true} if + * this set contained the element (or equivalently, if this set + * changed as a result of the call). (This set will not contain the + * element once the call returns.) + * + * @param o object to be removed from this set, if present + * @return {@code true} if this set contained the specified element + * @throws ClassCastException if the specified object cannot be compared + * with the elements currently in this set + * @throws NullPointerException if the specified element is null + * and this set uses natural ordering, or its comparator + * does not permit null elements + */ + public boolean remove(Object o) { + return m.remove(o)==PRESENT; + } + + /** + * Removes all of the elements from this set. + * The set will be empty after this call returns. + */ + public void clear() { + m.clear(); + } + + /** + * Adds all of the elements in the specified collection to this set. + * + * @param c collection containing elements to be added to this set + * @return {@code true} if this set changed as a result of the call + * @throws ClassCastException if the elements provided cannot be compared + * with the elements currently in the set + * @throws NullPointerException if the specified collection is null or + * if any element is null and this set uses natural ordering, or + * its comparator does not permit null elements + */ + public boolean addAll(Collection c) { + // Use linear-time version if applicable + if (m.size()==0 && c.size() > 0 && + c instanceof SortedSet && + m instanceof TreeMap7) { + SortedSet set = (SortedSet) c; + TreeMap7 map = (TreeMap7) m; + @SuppressWarnings("unchecked") + Comparator cc = (Comparator) set.comparator(); + Comparator mc = map.comparator(); + if (cc==mc || (cc != null && cc.equals(mc))) { + map.addAllForTreeSet(set, PRESENT); + return true; + } + } + return super.addAll(c); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} or {@code toElement} + * is null and this set uses natural ordering, or its comparator + * does not permit null elements + * @throws IllegalArgumentException {@inheritDoc} + * @since 1.6 + */ + public NavigableSet7 subSet(E fromElement, boolean fromInclusive, + E toElement, boolean toInclusive) { + return new TreeSet7(m.subMap(fromElement, fromInclusive, + toElement, toInclusive)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code toElement} is null and + * this set uses natural ordering, or its comparator does + * not permit null elements + * @throws IllegalArgumentException {@inheritDoc} + * @since 1.6 + */ + public NavigableSet7 headSet(E toElement, boolean inclusive) { + return new TreeSet7(m.headMap(toElement, inclusive)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} is null and + * this set uses natural ordering, or its comparator does + * not permit null elements + * @throws IllegalArgumentException {@inheritDoc} + * @since 1.6 + */ + public NavigableSet7 tailSet(E fromElement, boolean inclusive) { + return new TreeSet7(m.tailMap(fromElement, inclusive)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} or + * {@code toElement} is null and this set uses natural ordering, + * or its comparator does not permit null elements + * @throws IllegalArgumentException {@inheritDoc} + */ + public SortedSet subSet(E fromElement, E toElement) { + return subSet(fromElement, true, toElement, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code toElement} is null + * and this set uses natural ordering, or its comparator does + * not permit null elements + * @throws IllegalArgumentException {@inheritDoc} + */ + public SortedSet headSet(E toElement) { + return headSet(toElement, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} is null + * and this set uses natural ordering, or its comparator does + * not permit null elements + * @throws IllegalArgumentException {@inheritDoc} + */ + public SortedSet tailSet(E fromElement) { + return tailSet(fromElement, true); + } + + public Comparator comparator() { + return m.comparator(); + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E first() { + return m.firstKey(); + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E last() { + return m.lastKey(); + } + + // NavigableSet API methods + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * and this set uses natural ordering, or its comparator + * does not permit null elements + * @since 1.6 + */ + public E lower(E e) { + return m.lowerKey(e); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * and this set uses natural ordering, or its comparator + * does not permit null elements + * @since 1.6 + */ + public E floor(E e) { + return m.floorKey(e); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * and this set uses natural ordering, or its comparator + * does not permit null elements + * @since 1.6 + */ + public E ceiling(E e) { + return m.ceilingKey(e); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * and this set uses natural ordering, or its comparator + * does not permit null elements + * @since 1.6 + */ + public E higher(E e) { + return m.higherKey(e); + } + + /** + * @since 1.6 + */ + public E pollFirst() { + Map.Entry e = m.pollFirstEntry(); + return (e == null) ? null : e.getKey(); + } + + /** + * @since 1.6 + */ + public E pollLast() { + Map.Entry e = m.pollLastEntry(); + return (e == null) ? null : e.getKey(); + } + + /** + * Returns a shallow copy of this {@code TreeSet7} instance. (The elements + * themselves are not cloned.) + * + * @return a shallow copy of this set + */ + @SuppressWarnings("unchecked") + public Object clone() { + TreeSet7 clone = null; + try { + clone = (TreeSet7) super.clone(); + } catch (CloneNotSupportedException e) { + throw new InternalError(); + } + + clone.m = new TreeMap7(m); + return clone; + } + + /** + * Save the state of the {@code TreeSet7} instance to a stream (that is, + * serialize it). + * + * @serialData Emits the comparator used to order this set, or + * {@code null} if it obeys its elements' natural ordering + * (Object), followed by the size of the set (the number of + * elements it contains) (int), followed by all of its + * elements (each an Object) in order (as determined by the + * set's Comparator, or by the elements' natural ordering if + * the set has no Comparator). + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + // Write out any hidden stuff + s.defaultWriteObject(); + + // Write out Comparator + s.writeObject(m.comparator()); + + // Write out size + s.writeInt(m.size()); + + // Write out all elements in the proper order. + for (E e : m.keySet()) + s.writeObject(e); + } + + /** + * Reconstitute the {@code TreeSet7} instance from a stream (that is, + * deserialize it). + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + // Read in any hidden stuff + s.defaultReadObject(); + + // Read in Comparator + @SuppressWarnings("unchecked") + Comparator c = (Comparator) s.readObject(); + + // Create backing TreeMap + TreeMap7 tm; + if (c==null) + tm = new TreeMap7(); + else + tm = new TreeMap7(c); + m = tm; + + // Read in size + int size = s.readInt(); + + tm.readTreeSet(size, s, PRESENT); + } + + private static final long serialVersionUID = -2479143000061671589L; +} \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/ColumnHelper.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/ColumnHelper.java index e8751ef89..4b2bdc423 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/ColumnHelper.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/ColumnHelper.java @@ -25,9 +25,9 @@ import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Set; -import java.util.TreeSet; import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.util.java7_util.TreeSet7; import org.apache.poi.xssf.util.CTColComparator; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols; @@ -95,7 +95,7 @@ public class ColumnHelper { */ private void sweepCleanColumns(CTCols cols, CTCol[] flattenedColsArray, CTCol overrideColumn) { List flattenedCols = new ArrayList(Arrays.asList(flattenedColsArray)); - TreeSet currentElements = new TreeSet(new CTColByMaxComparator()); + TreeSet7 currentElements = new TreeSet7(new CTColByMaxComparator()); ListIterator flIter = flattenedCols.listIterator(); CTCol haveOverrideColumn = null; long lastMaxIndex = 0; From e790281425743a8d4f87ab9c1cba2379ea23dfda Mon Sep 17 00:00:00 2001 From: Andreas Beeker Date: Sun, 26 Jan 2014 15:38:11 +0000 Subject: [PATCH 10/11] This patch is not working as of license incompatibility - see http://www.apache.org/licenses/GPL-compatibility.html git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1561507 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/util/java7_util/AbstractMap7.java | 828 ------ .../poi/util/java7_util/AbstractSet7.java | 190 -- .../poi/util/java7_util/NavigableMap7.java | 429 --- .../poi/util/java7_util/NavigableSet7.java | 324 --- .../apache/poi/util/java7_util/TreeMap7.java | 2458 ----------------- .../apache/poi/util/java7_util/TreeSet7.java | 554 ---- .../xssf/usermodel/helpers/ColumnHelper.java | 4 +- 7 files changed, 2 insertions(+), 4785 deletions(-) delete mode 100644 src/ooxml/java/org/apache/poi/util/java7_util/AbstractMap7.java delete mode 100644 src/ooxml/java/org/apache/poi/util/java7_util/AbstractSet7.java delete mode 100644 src/ooxml/java/org/apache/poi/util/java7_util/NavigableMap7.java delete mode 100644 src/ooxml/java/org/apache/poi/util/java7_util/NavigableSet7.java delete mode 100644 src/ooxml/java/org/apache/poi/util/java7_util/TreeMap7.java delete mode 100644 src/ooxml/java/org/apache/poi/util/java7_util/TreeSet7.java diff --git a/src/ooxml/java/org/apache/poi/util/java7_util/AbstractMap7.java b/src/ooxml/java/org/apache/poi/util/java7_util/AbstractMap7.java deleted file mode 100644 index 6e65da7f2..000000000 --- a/src/ooxml/java/org/apache/poi/util/java7_util/AbstractMap7.java +++ /dev/null @@ -1,828 +0,0 @@ -/* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.apache.poi.util.java7_util; - -import java.util.AbstractCollection; -import java.util.AbstractSet; -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -/** - * This class provides a skeletal implementation of the Map - * interface, to minimize the effort required to implement this interface. - * - *

To implement an unmodifiable map, the programmer needs only to extend this - * class and provide an implementation for the entrySet method, which - * returns a set-view of the map's mappings. Typically, the returned set - * will, in turn, be implemented atop AbstractSet. This set should - * not support the add or remove methods, and its iterator - * should not support the remove method. - * - *

To implement a modifiable map, the programmer must additionally override - * this class's put method (which otherwise throws an - * UnsupportedOperationException), and the iterator returned by - * entrySet().iterator() must additionally implement its - * remove method. - * - *

The programmer should generally provide a void (no argument) and map - * constructor, as per the recommendation in the Map interface - * specification. - * - *

The documentation for each non-abstract method in this class describes its - * implementation in detail. Each of these methods may be overridden if the - * map being implemented admits a more efficient implementation. - * - *

This class is a member of the - * - * Java Collections Framework. - * - * @param the type of keys maintained by this map - * @param the type of mapped values - * - * @author Josh Bloch - * @author Neal Gafter - * @see Map - * @see Collection - * @since 1.2 - */ - -public abstract class AbstractMap7 implements Map { - /** - * Sole constructor. (For invocation by subclass constructors, typically - * implicit.) - */ - protected AbstractMap7() { - } - - // Query Operations - - /** - * {@inheritDoc} - * - *

This implementation returns entrySet().size(). - */ - public int size() { - return entrySet().size(); - } - - /** - * {@inheritDoc} - * - *

This implementation returns size() == 0. - */ - public boolean isEmpty() { - return size() == 0; - } - - /** - * {@inheritDoc} - * - *

This implementation iterates over entrySet() searching - * for an entry with the specified value. If such an entry is found, - * true is returned. If the iteration terminates without - * finding such an entry, false is returned. Note that this - * implementation requires linear time in the size of the map. - * - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - */ - public boolean containsValue(Object value) { - Iterator> i = entrySet().iterator(); - if (value==null) { - while (i.hasNext()) { - Entry e = i.next(); - if (e.getValue()==null) - return true; - } - } else { - while (i.hasNext()) { - Entry e = i.next(); - if (value.equals(e.getValue())) - return true; - } - } - return false; - } - - /** - * {@inheritDoc} - * - *

This implementation iterates over entrySet() searching - * for an entry with the specified key. If such an entry is found, - * true is returned. If the iteration terminates without - * finding such an entry, false is returned. Note that this - * implementation requires linear time in the size of the map; many - * implementations will override this method. - * - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - */ - public boolean containsKey(Object key) { - Iterator> i = entrySet().iterator(); - if (key==null) { - while (i.hasNext()) { - Entry e = i.next(); - if (e.getKey()==null) - return true; - } - } else { - while (i.hasNext()) { - Entry e = i.next(); - if (key.equals(e.getKey())) - return true; - } - } - return false; - } - - /** - * {@inheritDoc} - * - *

This implementation iterates over entrySet() searching - * for an entry with the specified key. If such an entry is found, - * the entry's value is returned. If the iteration terminates without - * finding such an entry, null is returned. Note that this - * implementation requires linear time in the size of the map; many - * implementations will override this method. - * - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - */ - public V get(Object key) { - Iterator> i = entrySet().iterator(); - if (key==null) { - while (i.hasNext()) { - Entry e = i.next(); - if (e.getKey()==null) - return e.getValue(); - } - } else { - while (i.hasNext()) { - Entry e = i.next(); - if (key.equals(e.getKey())) - return e.getValue(); - } - } - return null; - } - - - // Modification Operations - - /** - * {@inheritDoc} - * - *

This implementation always throws an - * UnsupportedOperationException. - * - * @throws UnsupportedOperationException {@inheritDoc} - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - * @throws IllegalArgumentException {@inheritDoc} - */ - public V put(K key, V value) { - throw new UnsupportedOperationException(); - } - - /** - * {@inheritDoc} - * - *

This implementation iterates over entrySet() searching for an - * entry with the specified key. If such an entry is found, its value is - * obtained with its getValue operation, the entry is removed - * from the collection (and the backing map) with the iterator's - * remove operation, and the saved value is returned. If the - * iteration terminates without finding such an entry, null is - * returned. Note that this implementation requires linear time in the - * size of the map; many implementations will override this method. - * - *

Note that this implementation throws an - * UnsupportedOperationException if the entrySet - * iterator does not support the remove method and this map - * contains a mapping for the specified key. - * - * @throws UnsupportedOperationException {@inheritDoc} - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - */ - public V remove(Object key) { - Iterator> i = entrySet().iterator(); - Entry correctEntry = null; - if (key==null) { - while (correctEntry==null && i.hasNext()) { - Entry e = i.next(); - if (e.getKey()==null) - correctEntry = e; - } - } else { - while (correctEntry==null && i.hasNext()) { - Entry e = i.next(); - if (key.equals(e.getKey())) - correctEntry = e; - } - } - - V oldValue = null; - if (correctEntry !=null) { - oldValue = correctEntry.getValue(); - i.remove(); - } - return oldValue; - } - - - // Bulk Operations - - /** - * {@inheritDoc} - * - *

This implementation iterates over the specified map's - * entrySet() collection, and calls this map's put - * operation once for each entry returned by the iteration. - * - *

Note that this implementation throws an - * UnsupportedOperationException if this map does not support - * the put operation and the specified map is nonempty. - * - * @throws UnsupportedOperationException {@inheritDoc} - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - * @throws IllegalArgumentException {@inheritDoc} - */ - public void putAll(Map m) { - for (Map.Entry e : m.entrySet()) - put(e.getKey(), e.getValue()); - } - - /** - * {@inheritDoc} - * - *

This implementation calls entrySet().clear(). - * - *

Note that this implementation throws an - * UnsupportedOperationException if the entrySet - * does not support the clear operation. - * - * @throws UnsupportedOperationException {@inheritDoc} - */ - public void clear() { - entrySet().clear(); - } - - - // Views - - /** - * Each of these fields are initialized to contain an instance of the - * appropriate view the first time this view is requested. The views are - * stateless, so there's no reason to create more than one of each. - */ - transient volatile Set keySet = null; - transient volatile Collection values = null; - - /** - * {@inheritDoc} - * - *

This implementation returns a set that subclasses {@link AbstractSet}. - * The subclass's iterator method returns a "wrapper object" over this - * map's entrySet() iterator. The size method - * delegates to this map's size method and the - * contains method delegates to this map's - * containsKey method. - * - *

The set is created the first time this method is called, - * and returned in response to all subsequent calls. No synchronization - * is performed, so there is a slight chance that multiple calls to this - * method will not all return the same set. - */ - public Set keySet() { - if (keySet == null) { - keySet = new AbstractSet() { - public Iterator iterator() { - return new Iterator() { - private Iterator> i = entrySet().iterator(); - - public boolean hasNext() { - return i.hasNext(); - } - - public K next() { - return i.next().getKey(); - } - - public void remove() { - i.remove(); - } - }; - } - - public int size() { - return AbstractMap7.this.size(); - } - - public boolean isEmpty() { - return AbstractMap7.this.isEmpty(); - } - - public void clear() { - AbstractMap7.this.clear(); - } - - public boolean contains(Object k) { - return AbstractMap7.this.containsKey(k); - } - }; - } - return keySet; - } - - /** - * {@inheritDoc} - * - *

This implementation returns a collection that subclasses {@link - * AbstractCollection}. The subclass's iterator method returns a - * "wrapper object" over this map's entrySet() iterator. - * The size method delegates to this map's size - * method and the contains method delegates to this map's - * containsValue method. - * - *

The collection is created the first time this method is called, and - * returned in response to all subsequent calls. No synchronization is - * performed, so there is a slight chance that multiple calls to this - * method will not all return the same collection. - */ - public Collection values() { - if (values == null) { - values = new AbstractCollection() { - public Iterator iterator() { - return new Iterator() { - private Iterator> i = entrySet().iterator(); - - public boolean hasNext() { - return i.hasNext(); - } - - public V next() { - return i.next().getValue(); - } - - public void remove() { - i.remove(); - } - }; - } - - public int size() { - return AbstractMap7.this.size(); - } - - public boolean isEmpty() { - return AbstractMap7.this.isEmpty(); - } - - public void clear() { - AbstractMap7.this.clear(); - } - - public boolean contains(Object v) { - return AbstractMap7.this.containsValue(v); - } - }; - } - return values; - } - - public abstract Set> entrySet(); - - - // Comparison and hashing - - /** - * Compares the specified object with this map for equality. Returns - * true if the given object is also a map and the two maps - * represent the same mappings. More formally, two maps m1 and - * m2 represent the same mappings if - * m1.entrySet().equals(m2.entrySet()). This ensures that the - * equals method works properly across different implementations - * of the Map interface. - * - *

This implementation first checks if the specified object is this map; - * if so it returns true. Then, it checks if the specified - * object is a map whose size is identical to the size of this map; if - * not, it returns false. If so, it iterates over this map's - * entrySet collection, and checks that the specified map - * contains each mapping that this map contains. If the specified map - * fails to contain such a mapping, false is returned. If the - * iteration completes, true is returned. - * - * @param o object to be compared for equality with this map - * @return true if the specified object is equal to this map - */ - public boolean equals(Object o) { - if (o == this) - return true; - - if (!(o instanceof Map)) - return false; - Map m = (Map) o; - if (m.size() != size()) - return false; - - try { - Iterator> i = entrySet().iterator(); - while (i.hasNext()) { - Entry e = i.next(); - K key = e.getKey(); - V value = e.getValue(); - if (value == null) { - if (!(m.get(key)==null && m.containsKey(key))) - return false; - } else { - if (!value.equals(m.get(key))) - return false; - } - } - } catch (ClassCastException unused) { - return false; - } catch (NullPointerException unused) { - return false; - } - - return true; - } - - /** - * Returns the hash code value for this map. The hash code of a map is - * defined to be the sum of the hash codes of each entry in the map's - * entrySet() view. This ensures that m1.equals(m2) - * implies that m1.hashCode()==m2.hashCode() for any two maps - * m1 and m2, as required by the general contract of - * {@link Object#hashCode}. - * - *

This implementation iterates over entrySet(), calling - * {@link Map.Entry#hashCode hashCode()} on each element (entry) in the - * set, and adding up the results. - * - * @return the hash code value for this map - * @see Map.Entry#hashCode() - * @see Object#equals(Object) - * @see Set#equals(Object) - */ - public int hashCode() { - int h = 0; - Iterator> i = entrySet().iterator(); - while (i.hasNext()) - h += i.next().hashCode(); - return h; - } - - /** - * Returns a string representation of this map. The string representation - * consists of a list of key-value mappings in the order returned by the - * map's entrySet view's iterator, enclosed in braces - * ("{}"). Adjacent mappings are separated by the characters - * ", " (comma and space). Each key-value mapping is rendered as - * the key followed by an equals sign ("=") followed by the - * associated value. Keys and values are converted to strings as by - * {@link String#valueOf(Object)}. - * - * @return a string representation of this map - */ - public String toString() { - Iterator> i = entrySet().iterator(); - if (! i.hasNext()) - return "{}"; - - StringBuilder sb = new StringBuilder(); - sb.append('{'); - for (;;) { - Entry e = i.next(); - K key = e.getKey(); - V value = e.getValue(); - sb.append(key == this ? "(this Map)" : key); - sb.append('='); - sb.append(value == this ? "(this Map)" : value); - if (! i.hasNext()) - return sb.append('}').toString(); - sb.append(',').append(' '); - } - } - - /** - * Returns a shallow copy of this AbstractMap7 instance: the keys - * and values themselves are not cloned. - * - * @return a shallow copy of this map - */ - protected Object clone() throws CloneNotSupportedException { - AbstractMap7 result = (AbstractMap7)super.clone(); - result.keySet = null; - result.values = null; - return result; - } - - /** - * Utility method for SimpleEntry and SimpleImmutableEntry. - * Test for equality, checking for nulls. - */ - private static boolean eq(Object o1, Object o2) { - return o1 == null ? o2 == null : o1.equals(o2); - } - - // Implementation Note: SimpleEntry and SimpleImmutableEntry - // are distinct unrelated classes, even though they share - // some code. Since you can't add or subtract final-ness - // of a field in a subclass, they can't share representations, - // and the amount of duplicated code is too small to warrant - // exposing a common abstract class. - - - /** - * An Entry maintaining a key and a value. The value may be - * changed using the setValue method. This class - * facilitates the process of building custom map - * implementations. For example, it may be convenient to return - * arrays of SimpleEntry instances in method - * Map.entrySet().toArray. - * - * @since 1.6 - */ - public static class SimpleEntry - implements Entry, java.io.Serializable - { - private static final long serialVersionUID = -8499721149061103585L; - - private final K key; - private V value; - - /** - * Creates an entry representing a mapping from the specified - * key to the specified value. - * - * @param key the key represented by this entry - * @param value the value represented by this entry - */ - public SimpleEntry(K key, V value) { - this.key = key; - this.value = value; - } - - /** - * Creates an entry representing the same mapping as the - * specified entry. - * - * @param entry the entry to copy - */ - public SimpleEntry(Entry entry) { - this.key = entry.getKey(); - this.value = entry.getValue(); - } - - /** - * Returns the key corresponding to this entry. - * - * @return the key corresponding to this entry - */ - public K getKey() { - return key; - } - - /** - * Returns the value corresponding to this entry. - * - * @return the value corresponding to this entry - */ - public V getValue() { - return value; - } - - /** - * Replaces the value corresponding to this entry with the specified - * value. - * - * @param value new value to be stored in this entry - * @return the old value corresponding to the entry - */ - public V setValue(V value) { - V oldValue = this.value; - this.value = value; - return oldValue; - } - - /** - * Compares the specified object with this entry for equality. - * Returns {@code true} if the given object is also a map entry and - * the two entries represent the same mapping. More formally, two - * entries {@code e1} and {@code e2} represent the same mapping - * if

-         *   (e1.getKey()==null ?
-         *    e2.getKey()==null :
-         *    e1.getKey().equals(e2.getKey()))
-         *   &&
-         *   (e1.getValue()==null ?
-         *    e2.getValue()==null :
-         *    e1.getValue().equals(e2.getValue()))
- * This ensures that the {@code equals} method works properly across - * different implementations of the {@code Map.Entry} interface. - * - * @param o object to be compared for equality with this map entry - * @return {@code true} if the specified object is equal to this map - * entry - * @see #hashCode - */ - public boolean equals(Object o) { - if (!(o instanceof Map.Entry)) - return false; - Map.Entry e = (Map.Entry)o; - return eq(key, e.getKey()) && eq(value, e.getValue()); - } - - /** - * Returns the hash code value for this map entry. The hash code - * of a map entry {@code e} is defined to be:
-         *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
-         *   (e.getValue()==null ? 0 : e.getValue().hashCode())
- * This ensures that {@code e1.equals(e2)} implies that - * {@code e1.hashCode()==e2.hashCode()} for any two Entries - * {@code e1} and {@code e2}, as required by the general - * contract of {@link Object#hashCode}. - * - * @return the hash code value for this map entry - * @see #equals - */ - public int hashCode() { - return (key == null ? 0 : key.hashCode()) ^ - (value == null ? 0 : value.hashCode()); - } - - /** - * Returns a String representation of this map entry. This - * implementation returns the string representation of this - * entry's key followed by the equals character ("=") - * followed by the string representation of this entry's value. - * - * @return a String representation of this map entry - */ - public String toString() { - return key + "=" + value; - } - - } - - /** - * An Entry maintaining an immutable key and value. This class - * does not support method setValue. This class may be - * convenient in methods that return thread-safe snapshots of - * key-value mappings. - * - * @since 1.6 - */ - public static class SimpleImmutableEntry - implements Entry, java.io.Serializable - { - private static final long serialVersionUID = 7138329143949025153L; - - private final K key; - private final V value; - - /** - * Creates an entry representing a mapping from the specified - * key to the specified value. - * - * @param key the key represented by this entry - * @param value the value represented by this entry - */ - public SimpleImmutableEntry(K key, V value) { - this.key = key; - this.value = value; - } - - /** - * Creates an entry representing the same mapping as the - * specified entry. - * - * @param entry the entry to copy - */ - public SimpleImmutableEntry(Entry entry) { - this.key = entry.getKey(); - this.value = entry.getValue(); - } - - /** - * Returns the key corresponding to this entry. - * - * @return the key corresponding to this entry - */ - public K getKey() { - return key; - } - - /** - * Returns the value corresponding to this entry. - * - * @return the value corresponding to this entry - */ - public V getValue() { - return value; - } - - /** - * Replaces the value corresponding to this entry with the specified - * value (optional operation). This implementation simply throws - * UnsupportedOperationException, as this class implements - * an immutable map entry. - * - * @param value new value to be stored in this entry - * @return (Does not return) - * @throws UnsupportedOperationException always - */ - public V setValue(V value) { - throw new UnsupportedOperationException(); - } - - /** - * Compares the specified object with this entry for equality. - * Returns {@code true} if the given object is also a map entry and - * the two entries represent the same mapping. More formally, two - * entries {@code e1} and {@code e2} represent the same mapping - * if
-         *   (e1.getKey()==null ?
-         *    e2.getKey()==null :
-         *    e1.getKey().equals(e2.getKey()))
-         *   &&
-         *   (e1.getValue()==null ?
-         *    e2.getValue()==null :
-         *    e1.getValue().equals(e2.getValue()))
- * This ensures that the {@code equals} method works properly across - * different implementations of the {@code Map.Entry} interface. - * - * @param o object to be compared for equality with this map entry - * @return {@code true} if the specified object is equal to this map - * entry - * @see #hashCode - */ - public boolean equals(Object o) { - if (!(o instanceof Map.Entry)) - return false; - Map.Entry e = (Map.Entry)o; - return eq(key, e.getKey()) && eq(value, e.getValue()); - } - - /** - * Returns the hash code value for this map entry. The hash code - * of a map entry {@code e} is defined to be:
-         *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
-         *   (e.getValue()==null ? 0 : e.getValue().hashCode())
- * This ensures that {@code e1.equals(e2)} implies that - * {@code e1.hashCode()==e2.hashCode()} for any two Entries - * {@code e1} and {@code e2}, as required by the general - * contract of {@link Object#hashCode}. - * - * @return the hash code value for this map entry - * @see #equals - */ - public int hashCode() { - return (key == null ? 0 : key.hashCode()) ^ - (value == null ? 0 : value.hashCode()); - } - - /** - * Returns a String representation of this map entry. This - * implementation returns the string representation of this - * entry's key followed by the equals character ("=") - * followed by the string representation of this entry's value. - * - * @return a String representation of this map entry - */ - public String toString() { - return key + "=" + value; - } - - } - -} \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/util/java7_util/AbstractSet7.java b/src/ooxml/java/org/apache/poi/util/java7_util/AbstractSet7.java deleted file mode 100644 index bb4fe0011..000000000 --- a/src/ooxml/java/org/apache/poi/util/java7_util/AbstractSet7.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.apache.poi.util.java7_util; - -import java.util.AbstractCollection; -import java.util.Collection; -import java.util.Iterator; -import java.util.Set; - -/** - * This class provides a skeletal implementation of the Set - * interface to minimize the effort required to implement this - * interface.

- * - * The process of implementing a set by extending this class is identical - * to that of implementing a Collection by extending AbstractCollection, - * except that all of the methods and constructors in subclasses of this - * class must obey the additional constraints imposed by the Set - * interface (for instance, the add method must not permit addition of - * multiple instances of an object to a set).

- * - * Note that this class does not override any of the implementations from - * the AbstractCollection class. It merely adds implementations - * for equals and hashCode.

- * - * This class is a member of the - * - * Java Collections Framework. - * - * @param the type of elements maintained by this set - * - * @author Josh Bloch - * @author Neal Gafter - * @see Collection - * @see AbstractCollection - * @see Set - * @since 1.2 - */ - -public abstract class AbstractSet7 extends AbstractCollection implements Set { - /** - * Sole constructor. (For invocation by subclass constructors, typically - * implicit.) - */ - protected AbstractSet7() { - } - - // Comparison and hashing - - /** - * Compares the specified object with this set for equality. Returns - * true if the given object is also a set, the two sets have - * the same size, and every member of the given set is contained in - * this set. This ensures that the equals method works - * properly across different implementations of the Set - * interface.

- * - * This implementation first checks if the specified object is this - * set; if so it returns true. Then, it checks if the - * specified object is a set whose size is identical to the size of - * this set; if not, it returns false. If so, it returns - * containsAll((Collection) o). - * - * @param o object to be compared for equality with this set - * @return true if the specified object is equal to this set - */ - public boolean equals(Object o) { - if (o == this) - return true; - - if (!(o instanceof Set)) - return false; - Collection c = (Collection) o; - if (c.size() != size()) - return false; - try { - return containsAll(c); - } catch (ClassCastException unused) { - return false; - } catch (NullPointerException unused) { - return false; - } - } - - /** - * Returns the hash code value for this set. The hash code of a set is - * defined to be the sum of the hash codes of the elements in the set, - * where the hash code of a null element is defined to be zero. - * This ensures that s1.equals(s2) implies that - * s1.hashCode()==s2.hashCode() for any two sets s1 - * and s2, as required by the general contract of - * {@link Object#hashCode}. - * - *

This implementation iterates over the set, calling the - * hashCode method on each element in the set, and adding up - * the results. - * - * @return the hash code value for this set - * @see Object#equals(Object) - * @see Set#equals(Object) - */ - public int hashCode() { - int h = 0; - Iterator i = iterator(); - while (i.hasNext()) { - E obj = i.next(); - if (obj != null) - h += obj.hashCode(); - } - return h; - } - - /** - * Removes from this set all of its elements that are contained in the - * specified collection (optional operation). If the specified - * collection is also a set, this operation effectively modifies this - * set so that its value is the asymmetric set difference of - * the two sets. - * - *

This implementation determines which is the smaller of this set - * and the specified collection, by invoking the size - * method on each. If this set has fewer elements, then the - * implementation iterates over this set, checking each element - * returned by the iterator in turn to see if it is contained in - * the specified collection. If it is so contained, it is removed - * from this set with the iterator's remove method. If - * the specified collection has fewer elements, then the - * implementation iterates over the specified collection, removing - * from this set each element returned by the iterator, using this - * set's remove method. - * - *

Note that this implementation will throw an - * UnsupportedOperationException if the iterator returned by the - * iterator method does not implement the remove method. - * - * @param c collection containing elements to be removed from this set - * @return true if this set changed as a result of the call - * @throws UnsupportedOperationException if the removeAll operation - * is not supported by this set - * @throws ClassCastException if the class of an element of this set - * is incompatible with the specified collection - * (optional) - * @throws NullPointerException if this set contains a null element and the - * specified collection does not permit null elements - * (optional), - * or if the specified collection is null - * @see #remove(Object) - * @see #contains(Object) - */ - public boolean removeAll(Collection c) { - boolean modified = false; - - if (size() > c.size()) { - for (Iterator i = c.iterator(); i.hasNext(); ) - modified |= remove(i.next()); - } else { - for (Iterator i = iterator(); i.hasNext(); ) { - if (c.contains(i.next())) { - i.remove(); - modified = true; - } - } - } - return modified; - } - -} \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/util/java7_util/NavigableMap7.java b/src/ooxml/java/org/apache/poi/util/java7_util/NavigableMap7.java deleted file mode 100644 index 45150d5b7..000000000 --- a/src/ooxml/java/org/apache/poi/util/java7_util/NavigableMap7.java +++ /dev/null @@ -1,429 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * This file is available under and governed by the GNU General Public - * License version 2 only, as published by the Free Software Foundation. - * However, the following notice accompanied the original version of this - * file: - * - * Written by Doug Lea and Josh Bloch with assistance from members of JCP - * JSR-166 Expert Group and released to the public domain, as explained at - * http://creativecommons.org/publicdomain/zero/1.0/ - */ - -package org.apache.poi.util.java7_util; - -import java.util.Collections; -import java.util.Comparator; -import java.util.Map; -import java.util.SortedMap; - -/** - * A {@link SortedMap} extended with navigation methods returning the - * closest matches for given search targets. Methods - * {@code lowerEntry}, {@code floorEntry}, {@code ceilingEntry}, - * and {@code higherEntry} return {@code Map.Entry} objects - * associated with keys respectively less than, less than or equal, - * greater than or equal, and greater than a given key, returning - * {@code null} if there is no such key. Similarly, methods - * {@code lowerKey}, {@code floorKey}, {@code ceilingKey}, and - * {@code higherKey} return only the associated keys. All of these - * methods are designed for locating, not traversing entries. - * - *

A {@code NavigableMap7} may be accessed and traversed in either - * ascending or descending key order. The {@code descendingMap} - * method returns a view of the map with the senses of all relational - * and directional methods inverted. The performance of ascending - * operations and views is likely to be faster than that of descending - * ones. Methods {@code subMap}, {@code headMap}, - * and {@code tailMap} differ from the like-named {@code - * SortedMap} methods in accepting additional arguments describing - * whether lower and upper bounds are inclusive versus exclusive. - * Submaps of any {@code NavigableMap7} must implement the {@code - * NavigableMap7} interface. - * - *

This interface additionally defines methods {@code firstEntry}, - * {@code pollFirstEntry}, {@code lastEntry}, and - * {@code pollLastEntry} that return and/or remove the least and - * greatest mappings, if any exist, else returning {@code null}. - * - *

Implementations of entry-returning methods are expected to - * return {@code Map.Entry} pairs representing snapshots of mappings - * at the time they were produced, and thus generally do not - * support the optional {@code Entry.setValue} method. Note however - * that it is possible to change mappings in the associated map using - * method {@code put}. - * - *

Methods - * {@link #subMap(Object, Object) subMap(K, K)}, - * {@link #headMap(Object) headMap(K)}, and - * {@link #tailMap(Object) tailMap(K)} - * are specified to return {@code SortedMap} to allow existing - * implementations of {@code SortedMap} to be compatibly retrofitted to - * implement {@code NavigableMap7}, but extensions and implementations - * of this interface are encouraged to override these methods to return - * {@code NavigableMap7}. Similarly, - * {@link #keySet()} can be overriden to return {@code NavigableSet}. - * - *

This interface is a member of the - * - * Java Collections Framework. - * - * @author Doug Lea - * @author Josh Bloch - * @param the type of keys maintained by this map - * @param the type of mapped values - * @since 1.6 - */ -public interface NavigableMap7 extends SortedMap { - /** - * Returns a key-value mapping associated with the greatest key - * strictly less than the given key, or {@code null} if there is - * no such key. - * - * @param key the key - * @return an entry with the greatest key less than {@code key}, - * or {@code null} if there is no such key - * @throws ClassCastException if the specified key cannot be compared - * with the keys currently in the map - * @throws NullPointerException if the specified key is null - * and this map does not permit null keys - */ - Map.Entry lowerEntry(K key); - - /** - * Returns the greatest key strictly less than the given key, or - * {@code null} if there is no such key. - * - * @param key the key - * @return the greatest key less than {@code key}, - * or {@code null} if there is no such key - * @throws ClassCastException if the specified key cannot be compared - * with the keys currently in the map - * @throws NullPointerException if the specified key is null - * and this map does not permit null keys - */ - K lowerKey(K key); - - /** - * Returns a key-value mapping associated with the greatest key - * less than or equal to the given key, or {@code null} if there - * is no such key. - * - * @param key the key - * @return an entry with the greatest key less than or equal to - * {@code key}, or {@code null} if there is no such key - * @throws ClassCastException if the specified key cannot be compared - * with the keys currently in the map - * @throws NullPointerException if the specified key is null - * and this map does not permit null keys - */ - Map.Entry floorEntry(K key); - - /** - * Returns the greatest key less than or equal to the given key, - * or {@code null} if there is no such key. - * - * @param key the key - * @return the greatest key less than or equal to {@code key}, - * or {@code null} if there is no such key - * @throws ClassCastException if the specified key cannot be compared - * with the keys currently in the map - * @throws NullPointerException if the specified key is null - * and this map does not permit null keys - */ - K floorKey(K key); - - /** - * Returns a key-value mapping associated with the least key - * greater than or equal to the given key, or {@code null} if - * there is no such key. - * - * @param key the key - * @return an entry with the least key greater than or equal to - * {@code key}, or {@code null} if there is no such key - * @throws ClassCastException if the specified key cannot be compared - * with the keys currently in the map - * @throws NullPointerException if the specified key is null - * and this map does not permit null keys - */ - Map.Entry ceilingEntry(K key); - - /** - * Returns the least key greater than or equal to the given key, - * or {@code null} if there is no such key. - * - * @param key the key - * @return the least key greater than or equal to {@code key}, - * or {@code null} if there is no such key - * @throws ClassCastException if the specified key cannot be compared - * with the keys currently in the map - * @throws NullPointerException if the specified key is null - * and this map does not permit null keys - */ - K ceilingKey(K key); - - /** - * Returns a key-value mapping associated with the least key - * strictly greater than the given key, or {@code null} if there - * is no such key. - * - * @param key the key - * @return an entry with the least key greater than {@code key}, - * or {@code null} if there is no such key - * @throws ClassCastException if the specified key cannot be compared - * with the keys currently in the map - * @throws NullPointerException if the specified key is null - * and this map does not permit null keys - */ - Map.Entry higherEntry(K key); - - /** - * Returns the least key strictly greater than the given key, or - * {@code null} if there is no such key. - * - * @param key the key - * @return the least key greater than {@code key}, - * or {@code null} if there is no such key - * @throws ClassCastException if the specified key cannot be compared - * with the keys currently in the map - * @throws NullPointerException if the specified key is null - * and this map does not permit null keys - */ - K higherKey(K key); - - /** - * Returns a key-value mapping associated with the least - * key in this map, or {@code null} if the map is empty. - * - * @return an entry with the least key, - * or {@code null} if this map is empty - */ - Map.Entry firstEntry(); - - /** - * Returns a key-value mapping associated with the greatest - * key in this map, or {@code null} if the map is empty. - * - * @return an entry with the greatest key, - * or {@code null} if this map is empty - */ - Map.Entry lastEntry(); - - /** - * Removes and returns a key-value mapping associated with - * the least key in this map, or {@code null} if the map is empty. - * - * @return the removed first entry of this map, - * or {@code null} if this map is empty - */ - Map.Entry pollFirstEntry(); - - /** - * Removes and returns a key-value mapping associated with - * the greatest key in this map, or {@code null} if the map is empty. - * - * @return the removed last entry of this map, - * or {@code null} if this map is empty - */ - Map.Entry pollLastEntry(); - - /** - * Returns a reverse order view of the mappings contained in this map. - * The descending map is backed by this map, so changes to the map are - * reflected in the descending map, and vice-versa. If either map is - * modified while an iteration over a collection view of either map - * is in progress (except through the iterator's own {@code remove} - * operation), the results of the iteration are undefined. - * - *

The returned map has an ordering equivalent to - * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator()). - * The expression {@code m.descendingMap().descendingMap()} returns a - * view of {@code m} essentially equivalent to {@code m}. - * - * @return a reverse order view of this map - */ - NavigableMap7 descendingMap(); - - /** - * Returns a {@link NavigableSet} view of the keys contained in this map. - * The set's iterator returns the keys in ascending order. - * The set is backed by the map, so changes to the map are reflected in - * the set, and vice-versa. If the map is modified while an iteration - * over the set is in progress (except through the iterator's own {@code - * remove} operation), the results of the iteration are undefined. The - * set supports element removal, which removes the corresponding mapping - * from the map, via the {@code Iterator.remove}, {@code Set.remove}, - * {@code removeAll}, {@code retainAll}, and {@code clear} operations. - * It does not support the {@code add} or {@code addAll} operations. - * - * @return a navigable set view of the keys in this map - */ - NavigableSet7 navigableKeySet(); - - /** - * Returns a reverse order {@link NavigableSet} view of the keys contained in this map. - * The set's iterator returns the keys in descending order. - * The set is backed by the map, so changes to the map are reflected in - * the set, and vice-versa. If the map is modified while an iteration - * over the set is in progress (except through the iterator's own {@code - * remove} operation), the results of the iteration are undefined. The - * set supports element removal, which removes the corresponding mapping - * from the map, via the {@code Iterator.remove}, {@code Set.remove}, - * {@code removeAll}, {@code retainAll}, and {@code clear} operations. - * It does not support the {@code add} or {@code addAll} operations. - * - * @return a reverse order navigable set view of the keys in this map - */ - NavigableSet7 descendingKeySet(); - - /** - * Returns a view of the portion of this map whose keys range from - * {@code fromKey} to {@code toKey}. If {@code fromKey} and - * {@code toKey} are equal, the returned map is empty unless - * {@code fromInclusive} and {@code toInclusive} are both true. The - * returned map is backed by this map, so changes in the returned map are - * reflected in this map, and vice-versa. The returned map supports all - * optional map operations that this map supports. - * - *

The returned map will throw an {@code IllegalArgumentException} - * on an attempt to insert a key outside of its range, or to construct a - * submap either of whose endpoints lie outside its range. - * - * @param fromKey low endpoint of the keys in the returned map - * @param fromInclusive {@code true} if the low endpoint - * is to be included in the returned view - * @param toKey high endpoint of the keys in the returned map - * @param toInclusive {@code true} if the high endpoint - * is to be included in the returned view - * @return a view of the portion of this map whose keys range from - * {@code fromKey} to {@code toKey} - * @throws ClassCastException if {@code fromKey} and {@code toKey} - * cannot be compared to one another using this map's comparator - * (or, if the map has no comparator, using natural ordering). - * Implementations may, but are not required to, throw this - * exception if {@code fromKey} or {@code toKey} - * cannot be compared to keys currently in the map. - * @throws NullPointerException if {@code fromKey} or {@code toKey} - * is null and this map does not permit null keys - * @throws IllegalArgumentException if {@code fromKey} is greater than - * {@code toKey}; or if this map itself has a restricted - * range, and {@code fromKey} or {@code toKey} lies - * outside the bounds of the range - */ - NavigableMap7 subMap(K fromKey, boolean fromInclusive, - K toKey, boolean toInclusive); - - /** - * Returns a view of the portion of this map whose keys are less than (or - * equal to, if {@code inclusive} is true) {@code toKey}. The returned - * map is backed by this map, so changes in the returned map are reflected - * in this map, and vice-versa. The returned map supports all optional - * map operations that this map supports. - * - *

The returned map will throw an {@code IllegalArgumentException} - * on an attempt to insert a key outside its range. - * - * @param toKey high endpoint of the keys in the returned map - * @param inclusive {@code true} if the high endpoint - * is to be included in the returned view - * @return a view of the portion of this map whose keys are less than - * (or equal to, if {@code inclusive} is true) {@code toKey} - * @throws ClassCastException if {@code toKey} is not compatible - * with this map's comparator (or, if the map has no comparator, - * if {@code toKey} does not implement {@link Comparable}). - * Implementations may, but are not required to, throw this - * exception if {@code toKey} cannot be compared to keys - * currently in the map. - * @throws NullPointerException if {@code toKey} is null - * and this map does not permit null keys - * @throws IllegalArgumentException if this map itself has a - * restricted range, and {@code toKey} lies outside the - * bounds of the range - */ - NavigableMap7 headMap(K toKey, boolean inclusive); - - /** - * Returns a view of the portion of this map whose keys are greater than (or - * equal to, if {@code inclusive} is true) {@code fromKey}. The returned - * map is backed by this map, so changes in the returned map are reflected - * in this map, and vice-versa. The returned map supports all optional - * map operations that this map supports. - * - *

The returned map will throw an {@code IllegalArgumentException} - * on an attempt to insert a key outside its range. - * - * @param fromKey low endpoint of the keys in the returned map - * @param inclusive {@code true} if the low endpoint - * is to be included in the returned view - * @return a view of the portion of this map whose keys are greater than - * (or equal to, if {@code inclusive} is true) {@code fromKey} - * @throws ClassCastException if {@code fromKey} is not compatible - * with this map's comparator (or, if the map has no comparator, - * if {@code fromKey} does not implement {@link Comparable}). - * Implementations may, but are not required to, throw this - * exception if {@code fromKey} cannot be compared to keys - * currently in the map. - * @throws NullPointerException if {@code fromKey} is null - * and this map does not permit null keys - * @throws IllegalArgumentException if this map itself has a - * restricted range, and {@code fromKey} lies outside the - * bounds of the range - */ - NavigableMap7 tailMap(K fromKey, boolean inclusive); - - /** - * {@inheritDoc} - * - *

Equivalent to {@code subMap(fromKey, true, toKey, false)}. - * - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - * @throws IllegalArgumentException {@inheritDoc} - */ - SortedMap subMap(K fromKey, K toKey); - - /** - * {@inheritDoc} - * - *

Equivalent to {@code headMap(toKey, false)}. - * - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - * @throws IllegalArgumentException {@inheritDoc} - */ - SortedMap headMap(K toKey); - - /** - * {@inheritDoc} - * - *

Equivalent to {@code tailMap(fromKey, true)}. - * - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - * @throws IllegalArgumentException {@inheritDoc} - */ - SortedMap tailMap(K fromKey); -} \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/util/java7_util/NavigableSet7.java b/src/ooxml/java/org/apache/poi/util/java7_util/NavigableSet7.java deleted file mode 100644 index bc515e727..000000000 --- a/src/ooxml/java/org/apache/poi/util/java7_util/NavigableSet7.java +++ /dev/null @@ -1,324 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * This file is available under and governed by the GNU General Public - * License version 2 only, as published by the Free Software Foundation. - * However, the following notice accompanied the original version of this - * file: - * - * Written by Doug Lea and Josh Bloch with assistance from members of JCP - * JSR-166 Expert Group and released to the public domain, as explained at - * http://creativecommons.org/publicdomain/zero/1.0/ - */ - -package org.apache.poi.util.java7_util; - -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.SortedSet; - -/** - * A {@link SortedSet} extended with navigation methods reporting - * closest matches for given search targets. Methods {@code lower}, - * {@code floor}, {@code ceiling}, and {@code higher} return elements - * respectively less than, less than or equal, greater than or equal, - * and greater than a given element, returning {@code null} if there - * is no such element. A {@code NavigableSet7} may be accessed and - * traversed in either ascending or descending order. The {@code - * descendingSet} method returns a view of the set with the senses of - * all relational and directional methods inverted. The performance of - * ascending operations and views is likely to be faster than that of - * descending ones. This interface additionally defines methods - * {@code pollFirst} and {@code pollLast} that return and remove the - * lowest and highest element, if one exists, else returning {@code - * null}. Methods {@code subSet}, {@code headSet}, - * and {@code tailSet} differ from the like-named {@code - * SortedSet} methods in accepting additional arguments describing - * whether lower and upper bounds are inclusive versus exclusive. - * Subsets of any {@code NavigableSet7} must implement the {@code - * NavigableSet7} interface. - * - *

The return values of navigation methods may be ambiguous in - * implementations that permit {@code null} elements. However, even - * in this case the result can be disambiguated by checking - * {@code contains(null)}. To avoid such issues, implementations of - * this interface are encouraged to not permit insertion of - * {@code null} elements. (Note that sorted sets of {@link - * Comparable} elements intrinsically do not permit {@code null}.) - * - *

Methods - * {@link #subSet(Object, Object) subSet(E, E)}, - * {@link #headSet(Object) headSet(E)}, and - * {@link #tailSet(Object) tailSet(E)} - * are specified to return {@code SortedSet} to allow existing - * implementations of {@code SortedSet} to be compatibly retrofitted to - * implement {@code NavigableSet7}, but extensions and implementations - * of this interface are encouraged to override these methods to return - * {@code NavigableSet7}. - * - *

This interface is a member of the - * - * Java Collections Framework. - * - * @author Doug Lea - * @author Josh Bloch - * @param the type of elements maintained by this set - * @since 1.6 - */ -public interface NavigableSet7 extends SortedSet { - /** - * Returns the greatest element in this set strictly less than the - * given element, or {@code null} if there is no such element. - * - * @param e the value to match - * @return the greatest element less than {@code e}, - * or {@code null} if there is no such element - * @throws ClassCastException if the specified element cannot be - * compared with the elements currently in the set - * @throws NullPointerException if the specified element is null - * and this set does not permit null elements - */ - E lower(E e); - - /** - * Returns the greatest element in this set less than or equal to - * the given element, or {@code null} if there is no such element. - * - * @param e the value to match - * @return the greatest element less than or equal to {@code e}, - * or {@code null} if there is no such element - * @throws ClassCastException if the specified element cannot be - * compared with the elements currently in the set - * @throws NullPointerException if the specified element is null - * and this set does not permit null elements - */ - E floor(E e); - - /** - * Returns the least element in this set greater than or equal to - * the given element, or {@code null} if there is no such element. - * - * @param e the value to match - * @return the least element greater than or equal to {@code e}, - * or {@code null} if there is no such element - * @throws ClassCastException if the specified element cannot be - * compared with the elements currently in the set - * @throws NullPointerException if the specified element is null - * and this set does not permit null elements - */ - E ceiling(E e); - - /** - * Returns the least element in this set strictly greater than the - * given element, or {@code null} if there is no such element. - * - * @param e the value to match - * @return the least element greater than {@code e}, - * or {@code null} if there is no such element - * @throws ClassCastException if the specified element cannot be - * compared with the elements currently in the set - * @throws NullPointerException if the specified element is null - * and this set does not permit null elements - */ - E higher(E e); - - /** - * Retrieves and removes the first (lowest) element, - * or returns {@code null} if this set is empty. - * - * @return the first element, or {@code null} if this set is empty - */ - E pollFirst(); - - /** - * Retrieves and removes the last (highest) element, - * or returns {@code null} if this set is empty. - * - * @return the last element, or {@code null} if this set is empty - */ - E pollLast(); - - /** - * Returns an iterator over the elements in this set, in ascending order. - * - * @return an iterator over the elements in this set, in ascending order - */ - Iterator iterator(); - - /** - * Returns a reverse order view of the elements contained in this set. - * The descending set is backed by this set, so changes to the set are - * reflected in the descending set, and vice-versa. If either set is - * modified while an iteration over either set is in progress (except - * through the iterator's own {@code remove} operation), the results of - * the iteration are undefined. - * - *

The returned set has an ordering equivalent to - * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator()). - * The expression {@code s.descendingSet().descendingSet()} returns a - * view of {@code s} essentially equivalent to {@code s}. - * - * @return a reverse order view of this set - */ - NavigableSet7 descendingSet(); - - /** - * Returns an iterator over the elements in this set, in descending order. - * Equivalent in effect to {@code descendingSet().iterator()}. - * - * @return an iterator over the elements in this set, in descending order - */ - Iterator descendingIterator(); - - /** - * Returns a view of the portion of this set whose elements range from - * {@code fromElement} to {@code toElement}. If {@code fromElement} and - * {@code toElement} are equal, the returned set is empty unless {@code - * fromInclusive} and {@code toInclusive} are both true. The returned set - * is backed by this set, so changes in the returned set are reflected in - * this set, and vice-versa. The returned set supports all optional set - * operations that this set supports. - * - *

The returned set will throw an {@code IllegalArgumentException} - * on an attempt to insert an element outside its range. - * - * @param fromElement low endpoint of the returned set - * @param fromInclusive {@code true} if the low endpoint - * is to be included in the returned view - * @param toElement high endpoint of the returned set - * @param toInclusive {@code true} if the high endpoint - * is to be included in the returned view - * @return a view of the portion of this set whose elements range from - * {@code fromElement}, inclusive, to {@code toElement}, exclusive - * @throws ClassCastException if {@code fromElement} and - * {@code toElement} cannot be compared to one another using this - * set's comparator (or, if the set has no comparator, using - * natural ordering). Implementations may, but are not required - * to, throw this exception if {@code fromElement} or - * {@code toElement} cannot be compared to elements currently in - * the set. - * @throws NullPointerException if {@code fromElement} or - * {@code toElement} is null and this set does - * not permit null elements - * @throws IllegalArgumentException if {@code fromElement} is - * greater than {@code toElement}; or if this set itself - * has a restricted range, and {@code fromElement} or - * {@code toElement} lies outside the bounds of the range. - */ - NavigableSet7 subSet(E fromElement, boolean fromInclusive, - E toElement, boolean toInclusive); - - /** - * Returns a view of the portion of this set whose elements are less than - * (or equal to, if {@code inclusive} is true) {@code toElement}. The - * returned set is backed by this set, so changes in the returned set are - * reflected in this set, and vice-versa. The returned set supports all - * optional set operations that this set supports. - * - *

The returned set will throw an {@code IllegalArgumentException} - * on an attempt to insert an element outside its range. - * - * @param toElement high endpoint of the returned set - * @param inclusive {@code true} if the high endpoint - * is to be included in the returned view - * @return a view of the portion of this set whose elements are less than - * (or equal to, if {@code inclusive} is true) {@code toElement} - * @throws ClassCastException if {@code toElement} is not compatible - * with this set's comparator (or, if the set has no comparator, - * if {@code toElement} does not implement {@link Comparable}). - * Implementations may, but are not required to, throw this - * exception if {@code toElement} cannot be compared to elements - * currently in the set. - * @throws NullPointerException if {@code toElement} is null and - * this set does not permit null elements - * @throws IllegalArgumentException if this set itself has a - * restricted range, and {@code toElement} lies outside the - * bounds of the range - */ - NavigableSet7 headSet(E toElement, boolean inclusive); - - /** - * Returns a view of the portion of this set whose elements are greater - * than (or equal to, if {@code inclusive} is true) {@code fromElement}. - * The returned set is backed by this set, so changes in the returned set - * are reflected in this set, and vice-versa. The returned set supports - * all optional set operations that this set supports. - * - *

The returned set will throw an {@code IllegalArgumentException} - * on an attempt to insert an element outside its range. - * - * @param fromElement low endpoint of the returned set - * @param inclusive {@code true} if the low endpoint - * is to be included in the returned view - * @return a view of the portion of this set whose elements are greater - * than or equal to {@code fromElement} - * @throws ClassCastException if {@code fromElement} is not compatible - * with this set's comparator (or, if the set has no comparator, - * if {@code fromElement} does not implement {@link Comparable}). - * Implementations may, but are not required to, throw this - * exception if {@code fromElement} cannot be compared to elements - * currently in the set. - * @throws NullPointerException if {@code fromElement} is null - * and this set does not permit null elements - * @throws IllegalArgumentException if this set itself has a - * restricted range, and {@code fromElement} lies outside the - * bounds of the range - */ - NavigableSet7 tailSet(E fromElement, boolean inclusive); - - /** - * {@inheritDoc} - * - *

Equivalent to {@code subSet(fromElement, true, toElement, false)}. - * - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - * @throws IllegalArgumentException {@inheritDoc} - */ - SortedSet subSet(E fromElement, E toElement); - - /** - * {@inheritDoc} - * - *

Equivalent to {@code headSet(toElement, false)}. - * - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - * @throws IllegalArgumentException {@inheritDoc} -na */ - SortedSet headSet(E toElement); - - /** - * {@inheritDoc} - * - *

Equivalent to {@code tailSet(fromElement, true)}. - * - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - * @throws IllegalArgumentException {@inheritDoc} - */ - SortedSet tailSet(E fromElement); -} \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/util/java7_util/TreeMap7.java b/src/ooxml/java/org/apache/poi/util/java7_util/TreeMap7.java deleted file mode 100644 index 591d8fb6d..000000000 --- a/src/ooxml/java/org/apache/poi/util/java7_util/TreeMap7.java +++ /dev/null @@ -1,2458 +0,0 @@ -/* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.apache.poi.util.java7_util; - -import java.io.IOException; -import java.util.AbstractCollection; -import java.util.AbstractSet; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.ConcurrentModificationException; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Set; -import java.util.SortedMap; -import java.util.SortedSet; - -/** - * A Red-Black tree based {@link NavigableMap7} implementation. - * The map is sorted according to the {@linkplain Comparable natural - * ordering} of its keys, or by a {@link Comparator} provided at map - * creation time, depending on which constructor is used. - * - *

This implementation provides guaranteed log(n) time cost for the - * {@code containsKey}, {@code get}, {@code put} and {@code remove} - * operations. Algorithms are adaptations of those in Cormen, Leiserson, and - * Rivest's Introduction to Algorithms. - * - *

Note that the ordering maintained by a tree map, like any sorted map, and - * whether or not an explicit comparator is provided, must be consistent - * with {@code equals} if this sorted map is to correctly implement the - * {@code Map} interface. (See {@code Comparable} or {@code Comparator} for a - * precise definition of consistent with equals.) This is so because - * the {@code Map} interface is defined in terms of the {@code equals} - * operation, but a sorted map performs all key comparisons using its {@code - * compareTo} (or {@code compare}) method, so two keys that are deemed equal by - * this method are, from the standpoint of the sorted map, equal. The behavior - * of a sorted map is well-defined even if its ordering is - * inconsistent with {@code equals}; it just fails to obey the general contract - * of the {@code Map} interface. - * - *

Note that this implementation is not synchronized. - * If multiple threads access a map concurrently, and at least one of the - * threads modifies the map structurally, it must be synchronized - * externally. (A structural modification is any operation that adds or - * deletes one or more mappings; merely changing the value associated - * with an existing key is not a structural modification.) This is - * typically accomplished by synchronizing on some object that naturally - * encapsulates the map. - * If no such object exists, the map should be "wrapped" using the - * {@link Collections#synchronizedSortedMap Collections.synchronizedSortedMap} - * method. This is best done at creation time, to prevent accidental - * unsynchronized access to the map:

- *   SortedMap m = Collections.synchronizedSortedMap(new TreeMap7(...));
- * - *

The iterators returned by the {@code iterator} method of the collections - * returned by all of this class's "collection view methods" are - * fail-fast: if the map is structurally modified at any time after - * the iterator is created, in any way except through the iterator's own - * {@code remove} method, the iterator will throw a {@link - * ConcurrentModificationException}. Thus, in the face of concurrent - * modification, the iterator fails quickly and cleanly, rather than risking - * arbitrary, non-deterministic behavior at an undetermined time in the future. - * - *

Note that the fail-fast behavior of an iterator cannot be guaranteed - * as it is, generally speaking, impossible to make any hard guarantees in the - * presence of unsynchronized concurrent modification. Fail-fast iterators - * throw {@code ConcurrentModificationException} on a best-effort basis. - * Therefore, it would be wrong to write a program that depended on this - * exception for its correctness: the fail-fast behavior of iterators - * should be used only to detect bugs. - * - *

All {@code Map.Entry} pairs returned by methods in this class - * and its views represent snapshots of mappings at the time they were - * produced. They do not support the {@code Entry.setValue} - * method. (Note however that it is possible to change mappings in the - * associated map using {@code put}.) - * - *

This class is a member of the - * - * Java Collections Framework. - * - * @param the type of keys maintained by this map - * @param the type of mapped values - * - * @author Josh Bloch and Doug Lea - * @see Map - * @see HashMap - * @see Hashtable - * @see Comparable - * @see Comparator - * @see Collection - * @since 1.2 - */ - -public class TreeMap7 - extends AbstractMap7 - implements NavigableMap7, Cloneable, java.io.Serializable -{ - /** - * The comparator used to maintain order in this tree map, or - * null if it uses the natural ordering of its keys. - * - * @serial - */ - private final Comparator comparator; - - private transient Entry root = null; - - /** - * The number of entries in the tree - */ - private transient int size = 0; - - /** - * The number of structural modifications to the tree. - */ - private transient int modCount = 0; - - /** - * Constructs a new, empty tree map, using the natural ordering of its - * keys. All keys inserted into the map must implement the {@link - * Comparable} interface. Furthermore, all such keys must be - * mutually comparable: {@code k1.compareTo(k2)} must not throw - * a {@code ClassCastException} for any keys {@code k1} and - * {@code k2} in the map. If the user attempts to put a key into the - * map that violates this constraint (for example, the user attempts to - * put a string key into a map whose keys are integers), the - * {@code put(Object key, Object value)} call will throw a - * {@code ClassCastException}. - */ - public TreeMap7() { - comparator = null; - } - - /** - * Constructs a new, empty tree map, ordered according to the given - * comparator. All keys inserted into the map must be mutually - * comparable by the given comparator: {@code comparator.compare(k1, - * k2)} must not throw a {@code ClassCastException} for any keys - * {@code k1} and {@code k2} in the map. If the user attempts to put - * a key into the map that violates this constraint, the {@code put(Object - * key, Object value)} call will throw a - * {@code ClassCastException}. - * - * @param comparator the comparator that will be used to order this map. - * If {@code null}, the {@linkplain Comparable natural - * ordering} of the keys will be used. - */ - public TreeMap7(Comparator comparator) { - this.comparator = comparator; - } - - /** - * Constructs a new tree map containing the same mappings as the given - * map, ordered according to the natural ordering of its keys. - * All keys inserted into the new map must implement the {@link - * Comparable} interface. Furthermore, all such keys must be - * mutually comparable: {@code k1.compareTo(k2)} must not throw - * a {@code ClassCastException} for any keys {@code k1} and - * {@code k2} in the map. This method runs in n*log(n) time. - * - * @param m the map whose mappings are to be placed in this map - * @throws ClassCastException if the keys in m are not {@link Comparable}, - * or are not mutually comparable - * @throws NullPointerException if the specified map is null - */ - public TreeMap7(Map m) { - comparator = null; - putAll(m); - } - - /** - * Constructs a new tree map containing the same mappings and - * using the same ordering as the specified sorted map. This - * method runs in linear time. - * - * @param m the sorted map whose mappings are to be placed in this map, - * and whose comparator is to be used to sort this map - * @throws NullPointerException if the specified map is null - */ - public TreeMap7(SortedMap m) { - comparator = m.comparator(); - try { - buildFromSorted(m.size(), m.entrySet().iterator(), null, null); - } catch (java.io.IOException cannotHappen) { - } catch (ClassNotFoundException cannotHappen) { - } - } - - - // Query Operations - - /** - * Returns the number of key-value mappings in this map. - * - * @return the number of key-value mappings in this map - */ - public int size() { - return size; - } - - /** - * Returns {@code true} if this map contains a mapping for the specified - * key. - * - * @param key key whose presence in this map is to be tested - * @return {@code true} if this map contains a mapping for the - * specified key - * @throws ClassCastException if the specified key cannot be compared - * with the keys currently in the map - * @throws NullPointerException if the specified key is null - * and this map uses natural ordering, or its comparator - * does not permit null keys - */ - public boolean containsKey(Object key) { - return getEntry(key) != null; - } - - /** - * Returns {@code true} if this map maps one or more keys to the - * specified value. More formally, returns {@code true} if and only if - * this map contains at least one mapping to a value {@code v} such - * that {@code (value==null ? v==null : value.equals(v))}. This - * operation will probably require time linear in the map size for - * most implementations. - * - * @param value value whose presence in this map is to be tested - * @return {@code true} if a mapping to {@code value} exists; - * {@code false} otherwise - * @since 1.2 - */ - public boolean containsValue(Object value) { - for (Entry e = getFirstEntry(); e != null; e = successor(e)) - if (valEquals(value, e.value)) - return true; - return false; - } - - /** - * Returns the value to which the specified key is mapped, - * or {@code null} if this map contains no mapping for the key. - * - *

More formally, if this map contains a mapping from a key - * {@code k} to a value {@code v} such that {@code key} compares - * equal to {@code k} according to the map's ordering, then this - * method returns {@code v}; otherwise it returns {@code null}. - * (There can be at most one such mapping.) - * - *

A return value of {@code null} does not necessarily - * indicate that the map contains no mapping for the key; it's also - * possible that the map explicitly maps the key to {@code null}. - * The {@link #containsKey containsKey} operation may be used to - * distinguish these two cases. - * - * @throws ClassCastException if the specified key cannot be compared - * with the keys currently in the map - * @throws NullPointerException if the specified key is null - * and this map uses natural ordering, or its comparator - * does not permit null keys - */ - public V get(Object key) { - Entry p = getEntry(key); - return (p==null ? null : p.value); - } - - public Comparator comparator() { - return comparator; - } - - /** - * @throws NoSuchElementException {@inheritDoc} - */ - public K firstKey() { - return key(getFirstEntry()); - } - - /** - * @throws NoSuchElementException {@inheritDoc} - */ - public K lastKey() { - return key(getLastEntry()); - } - - /** - * Copies all of the mappings from the specified map to this map. - * These mappings replace any mappings that this map had for any - * of the keys currently in the specified map. - * - * @param map mappings to be stored in this map - * @throws ClassCastException if the class of a key or value in - * the specified map prevents it from being stored in this map - * @throws NullPointerException if the specified map is null or - * the specified map contains a null key and this map does not - * permit null keys - */ - public void putAll(Map map) { - int mapSize = map.size(); - if (size==0 && mapSize!=0 && map instanceof SortedMap) { - Comparator c = ((SortedMap)map).comparator(); - if (c == comparator || (c != null && c.equals(comparator))) { - ++modCount; - try { - buildFromSorted(mapSize, map.entrySet().iterator(), - null, null); - } catch (java.io.IOException cannotHappen) { - } catch (ClassNotFoundException cannotHappen) { - } - return; - } - } - super.putAll(map); - } - - /** - * Returns this map's entry for the given key, or {@code null} if the map - * does not contain an entry for the key. - * - * @return this map's entry for the given key, or {@code null} if the map - * does not contain an entry for the key - * @throws ClassCastException if the specified key cannot be compared - * with the keys currently in the map - * @throws NullPointerException if the specified key is null - * and this map uses natural ordering, or its comparator - * does not permit null keys - */ - final Entry getEntry(Object key) { - // Offload comparator-based version for sake of performance - if (comparator != null) - return getEntryUsingComparator(key); - if (key == null) - throw new NullPointerException(); - Comparable k = (Comparable) key; - Entry p = root; - while (p != null) { - int cmp = k.compareTo(p.key); - if (cmp < 0) - p = p.left; - else if (cmp > 0) - p = p.right; - else - return p; - } - return null; - } - - /** - * Version of getEntry using comparator. Split off from getEntry - * for performance. (This is not worth doing for most methods, - * that are less dependent on comparator performance, but is - * worthwhile here.) - */ - final Entry getEntryUsingComparator(Object key) { - K k = (K) key; - Comparator cpr = comparator; - if (cpr != null) { - Entry p = root; - while (p != null) { - int cmp = cpr.compare(k, p.key); - if (cmp < 0) - p = p.left; - else if (cmp > 0) - p = p.right; - else - return p; - } - } - return null; - } - - /** - * Gets the entry corresponding to the specified key; if no such entry - * exists, returns the entry for the least key greater than the specified - * key; if no such entry exists (i.e., the greatest key in the Tree is less - * than the specified key), returns {@code null}. - */ - final Entry getCeilingEntry(K key) { - Entry p = root; - while (p != null) { - int cmp = compare(key, p.key); - if (cmp < 0) { - if (p.left != null) - p = p.left; - else - return p; - } else if (cmp > 0) { - if (p.right != null) { - p = p.right; - } else { - Entry parent = p.parent; - Entry ch = p; - while (parent != null && ch == parent.right) { - ch = parent; - parent = parent.parent; - } - return parent; - } - } else - return p; - } - return null; - } - - /** - * Gets the entry corresponding to the specified key; if no such entry - * exists, returns the entry for the greatest key less than the specified - * key; if no such entry exists, returns {@code null}. - */ - final Entry getFloorEntry(K key) { - Entry p = root; - while (p != null) { - int cmp = compare(key, p.key); - if (cmp > 0) { - if (p.right != null) - p = p.right; - else - return p; - } else if (cmp < 0) { - if (p.left != null) { - p = p.left; - } else { - Entry parent = p.parent; - Entry ch = p; - while (parent != null && ch == parent.left) { - ch = parent; - parent = parent.parent; - } - return parent; - } - } else - return p; - - } - return null; - } - - /** - * Gets the entry for the least key greater than the specified - * key; if no such entry exists, returns the entry for the least - * key greater than the specified key; if no such entry exists - * returns {@code null}. - */ - final Entry getHigherEntry(K key) { - Entry p = root; - while (p != null) { - int cmp = compare(key, p.key); - if (cmp < 0) { - if (p.left != null) - p = p.left; - else - return p; - } else { - if (p.right != null) { - p = p.right; - } else { - Entry parent = p.parent; - Entry ch = p; - while (parent != null && ch == parent.right) { - ch = parent; - parent = parent.parent; - } - return parent; - } - } - } - return null; - } - - /** - * Returns the entry for the greatest key less than the specified key; if - * no such entry exists (i.e., the least key in the Tree is greater than - * the specified key), returns {@code null}. - */ - final Entry getLowerEntry(K key) { - Entry p = root; - while (p != null) { - int cmp = compare(key, p.key); - if (cmp > 0) { - if (p.right != null) - p = p.right; - else - return p; - } else { - if (p.left != null) { - p = p.left; - } else { - Entry parent = p.parent; - Entry ch = p; - while (parent != null && ch == parent.left) { - ch = parent; - parent = parent.parent; - } - return parent; - } - } - } - return null; - } - - /** - * Associates the specified value with the specified key in this map. - * If the map previously contained a mapping for the key, the old - * value is replaced. - * - * @param key key with which the specified value is to be associated - * @param value value to be associated with the specified key - * - * @return the previous value associated with {@code key}, or - * {@code null} if there was no mapping for {@code key}. - * (A {@code null} return can also indicate that the map - * previously associated {@code null} with {@code key}.) - * @throws ClassCastException if the specified key cannot be compared - * with the keys currently in the map - * @throws NullPointerException if the specified key is null - * and this map uses natural ordering, or its comparator - * does not permit null keys - */ - public V put(K key, V value) { - Entry t = root; - if (t == null) { - compare(key, key); // type (and possibly null) check - - root = new Entry(key, value, null); - size = 1; - modCount++; - return null; - } - int cmp; - Entry parent; - // split comparator and comparable paths - Comparator cpr = comparator; - if (cpr != null) { - do { - parent = t; - cmp = cpr.compare(key, t.key); - if (cmp < 0) - t = t.left; - else if (cmp > 0) - t = t.right; - else - return t.setValue(value); - } while (t != null); - } - else { - if (key == null) - throw new NullPointerException(); - Comparable k = (Comparable) key; - do { - parent = t; - cmp = k.compareTo(t.key); - if (cmp < 0) - t = t.left; - else if (cmp > 0) - t = t.right; - else - return t.setValue(value); - } while (t != null); - } - Entry e = new Entry(key, value, parent); - if (cmp < 0) - parent.left = e; - else - parent.right = e; - fixAfterInsertion(e); - size++; - modCount++; - return null; - } - - /** - * Removes the mapping for this key from this TreeMap7 if present. - * - * @param key key for which mapping should be removed - * @return the previous value associated with {@code key}, or - * {@code null} if there was no mapping for {@code key}. - * (A {@code null} return can also indicate that the map - * previously associated {@code null} with {@code key}.) - * @throws ClassCastException if the specified key cannot be compared - * with the keys currently in the map - * @throws NullPointerException if the specified key is null - * and this map uses natural ordering, or its comparator - * does not permit null keys - */ - public V remove(Object key) { - Entry p = getEntry(key); - if (p == null) - return null; - - V oldValue = p.value; - deleteEntry(p); - return oldValue; - } - - /** - * Removes all of the mappings from this map. - * The map will be empty after this call returns. - */ - public void clear() { - modCount++; - size = 0; - root = null; - } - - /** - * Returns a shallow copy of this {@code TreeMap7} instance. (The keys and - * values themselves are not cloned.) - * - * @return a shallow copy of this map - */ - public Object clone() { - TreeMap7 clone = null; - try { - clone = (TreeMap7) super.clone(); - } catch (CloneNotSupportedException e) { - throw new InternalError(); - } - - // Put clone into "virgin" state (except for comparator) - clone.root = null; - clone.size = 0; - clone.modCount = 0; - clone.entrySet = null; - clone.navigableKeySet = null; - clone.descendingMap = null; - - // Initialize clone with our mappings - try { - clone.buildFromSorted(size, entrySet().iterator(), null, null); - } catch (java.io.IOException cannotHappen) { - } catch (ClassNotFoundException cannotHappen) { - } - - return clone; - } - - // NavigableMap7 API methods - - /** - * @since 1.6 - */ - public Map.Entry firstEntry() { - return exportEntry(getFirstEntry()); - } - - /** - * @since 1.6 - */ - public Map.Entry lastEntry() { - return exportEntry(getLastEntry()); - } - - /** - * @since 1.6 - */ - public Map.Entry pollFirstEntry() { - Entry p = getFirstEntry(); - Map.Entry result = exportEntry(p); - if (p != null) - deleteEntry(p); - return result; - } - - /** - * @since 1.6 - */ - public Map.Entry pollLastEntry() { - Entry p = getLastEntry(); - Map.Entry result = exportEntry(p); - if (p != null) - deleteEntry(p); - return result; - } - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if the specified key is null - * and this map uses natural ordering, or its comparator - * does not permit null keys - * @since 1.6 - */ - public Map.Entry lowerEntry(K key) { - return exportEntry(getLowerEntry(key)); - } - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if the specified key is null - * and this map uses natural ordering, or its comparator - * does not permit null keys - * @since 1.6 - */ - public K lowerKey(K key) { - return keyOrNull(getLowerEntry(key)); - } - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if the specified key is null - * and this map uses natural ordering, or its comparator - * does not permit null keys - * @since 1.6 - */ - public Map.Entry floorEntry(K key) { - return exportEntry(getFloorEntry(key)); - } - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if the specified key is null - * and this map uses natural ordering, or its comparator - * does not permit null keys - * @since 1.6 - */ - public K floorKey(K key) { - return keyOrNull(getFloorEntry(key)); - } - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if the specified key is null - * and this map uses natural ordering, or its comparator - * does not permit null keys - * @since 1.6 - */ - public Map.Entry ceilingEntry(K key) { - return exportEntry(getCeilingEntry(key)); - } - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if the specified key is null - * and this map uses natural ordering, or its comparator - * does not permit null keys - * @since 1.6 - */ - public K ceilingKey(K key) { - return keyOrNull(getCeilingEntry(key)); - } - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if the specified key is null - * and this map uses natural ordering, or its comparator - * does not permit null keys - * @since 1.6 - */ - public Map.Entry higherEntry(K key) { - return exportEntry(getHigherEntry(key)); - } - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if the specified key is null - * and this map uses natural ordering, or its comparator - * does not permit null keys - * @since 1.6 - */ - public K higherKey(K key) { - return keyOrNull(getHigherEntry(key)); - } - - // Views - - /** - * Fields initialized to contain an instance of the entry set view - * the first time this view is requested. Views are stateless, so - * there's no reason to create more than one. - */ - private transient EntrySet entrySet = null; - private transient KeySet navigableKeySet = null; - private transient NavigableMap7 descendingMap = null; - - /** - * Returns a {@link Set} view of the keys contained in this map. - * The set's iterator returns the keys in ascending order. - * The set is backed by the map, so changes to the map are - * reflected in the set, and vice-versa. If the map is modified - * while an iteration over the set is in progress (except through - * the iterator's own {@code remove} operation), the results of - * the iteration are undefined. The set supports element removal, - * which removes the corresponding mapping from the map, via the - * {@code Iterator.remove}, {@code Set.remove}, - * {@code removeAll}, {@code retainAll}, and {@code clear} - * operations. It does not support the {@code add} or {@code addAll} - * operations. - */ - public Set keySet() { - return navigableKeySet(); - } - - /** - * @since 1.6 - */ - public NavigableSet7 navigableKeySet() { - KeySet nks = navigableKeySet; - return (nks != null) ? nks : (navigableKeySet = new KeySet(this)); - } - - /** - * @since 1.6 - */ - public NavigableSet7 descendingKeySet() { - return descendingMap().navigableKeySet(); - } - - /** - * Returns a {@link Collection} view of the values contained in this map. - * The collection's iterator returns the values in ascending order - * of the corresponding keys. - * The collection is backed by the map, so changes to the map are - * reflected in the collection, and vice-versa. If the map is - * modified while an iteration over the collection is in progress - * (except through the iterator's own {@code remove} operation), - * the results of the iteration are undefined. The collection - * supports element removal, which removes the corresponding - * mapping from the map, via the {@code Iterator.remove}, - * {@code Collection.remove}, {@code removeAll}, - * {@code retainAll} and {@code clear} operations. It does not - * support the {@code add} or {@code addAll} operations. - */ - public Collection values() { - Collection vs = values; - return (vs != null) ? vs : (values = new Values()); - } - - /** - * Returns a {@link Set} view of the mappings contained in this map. - * The set's iterator returns the entries in ascending key order. - * The set is backed by the map, so changes to the map are - * reflected in the set, and vice-versa. If the map is modified - * while an iteration over the set is in progress (except through - * the iterator's own {@code remove} operation, or through the - * {@code setValue} operation on a map entry returned by the - * iterator) the results of the iteration are undefined. The set - * supports element removal, which removes the corresponding - * mapping from the map, via the {@code Iterator.remove}, - * {@code Set.remove}, {@code removeAll}, {@code retainAll} and - * {@code clear} operations. It does not support the - * {@code add} or {@code addAll} operations. - */ - public Set> entrySet() { - EntrySet es = entrySet; - return (es != null) ? es : (entrySet = new EntrySet()); - } - - /** - * @since 1.6 - */ - public NavigableMap7 descendingMap() { - NavigableMap7 km = descendingMap; - return (km != null) ? km : - (descendingMap = new DescendingSubMap(this, - true, null, true, - true, null, true)); - } - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if {@code fromKey} or {@code toKey} is - * null and this map uses natural ordering, or its comparator - * does not permit null keys - * @throws IllegalArgumentException {@inheritDoc} - * @since 1.6 - */ - public NavigableMap7 subMap(K fromKey, boolean fromInclusive, - K toKey, boolean toInclusive) { - return new AscendingSubMap(this, - false, fromKey, fromInclusive, - false, toKey, toInclusive); - } - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if {@code toKey} is null - * and this map uses natural ordering, or its comparator - * does not permit null keys - * @throws IllegalArgumentException {@inheritDoc} - * @since 1.6 - */ - public NavigableMap7 headMap(K toKey, boolean inclusive) { - return new AscendingSubMap(this, - true, null, true, - false, toKey, inclusive); - } - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if {@code fromKey} is null - * and this map uses natural ordering, or its comparator - * does not permit null keys - * @throws IllegalArgumentException {@inheritDoc} - * @since 1.6 - */ - public NavigableMap7 tailMap(K fromKey, boolean inclusive) { - return new AscendingSubMap(this, - false, fromKey, inclusive, - true, null, true); - } - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if {@code fromKey} or {@code toKey} is - * null and this map uses natural ordering, or its comparator - * does not permit null keys - * @throws IllegalArgumentException {@inheritDoc} - */ - public SortedMap subMap(K fromKey, K toKey) { - return subMap(fromKey, true, toKey, false); - } - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if {@code toKey} is null - * and this map uses natural ordering, or its comparator - * does not permit null keys - * @throws IllegalArgumentException {@inheritDoc} - */ - public SortedMap headMap(K toKey) { - return headMap(toKey, false); - } - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if {@code fromKey} is null - * and this map uses natural ordering, or its comparator - * does not permit null keys - * @throws IllegalArgumentException {@inheritDoc} - */ - public SortedMap tailMap(K fromKey) { - return tailMap(fromKey, true); - } - - // View class support - - class Values extends AbstractCollection { - public Iterator iterator() { - return new ValueIterator(getFirstEntry()); - } - - public int size() { - return TreeMap7.this.size(); - } - - public boolean contains(Object o) { - return TreeMap7.this.containsValue(o); - } - - public boolean remove(Object o) { - for (Entry e = getFirstEntry(); e != null; e = successor(e)) { - if (valEquals(e.getValue(), o)) { - deleteEntry(e); - return true; - } - } - return false; - } - - public void clear() { - TreeMap7.this.clear(); - } - } - - class EntrySet extends AbstractSet> { - public Iterator> iterator() { - return new EntryIterator(getFirstEntry()); - } - - public boolean contains(Object o) { - if (!(o instanceof Map.Entry)) - return false; - Map.Entry entry = (Map.Entry) o; - V value = entry.getValue(); - Entry p = getEntry(entry.getKey()); - return p != null && valEquals(p.getValue(), value); - } - - public boolean remove(Object o) { - if (!(o instanceof Map.Entry)) - return false; - Map.Entry entry = (Map.Entry) o; - V value = entry.getValue(); - Entry p = getEntry(entry.getKey()); - if (p != null && valEquals(p.getValue(), value)) { - deleteEntry(p); - return true; - } - return false; - } - - public int size() { - return TreeMap7.this.size(); - } - - public void clear() { - TreeMap7.this.clear(); - } - } - - /* - * Unlike Values and EntrySet, the KeySet class is static, - * delegating to a NavigableMap7 to allow use by SubMaps, which - * outweighs the ugliness of needing type-tests for the following - * Iterator methods that are defined appropriately in main versus - * submap classes. - */ - - Iterator keyIterator() { - return new KeyIterator(getFirstEntry()); - } - - Iterator descendingKeyIterator() { - return new DescendingKeyIterator(getLastEntry()); - } - - static final class KeySet extends AbstractSet implements NavigableSet7 { - private final NavigableMap7 m; - KeySet(NavigableMap7 map) { m = map; } - - public Iterator iterator() { - if (m instanceof TreeMap7) - return ((TreeMap7)m).keyIterator(); - else - return (Iterator)(((TreeMap7.NavigableSubMap)m).keyIterator()); - } - - public Iterator descendingIterator() { - if (m instanceof TreeMap7) - return ((TreeMap7)m).descendingKeyIterator(); - else - return (Iterator)(((TreeMap7.NavigableSubMap)m).descendingKeyIterator()); - } - - public int size() { return m.size(); } - public boolean isEmpty() { return m.isEmpty(); } - public boolean contains(Object o) { return m.containsKey(o); } - public void clear() { m.clear(); } - public E lower(E e) { return m.lowerKey(e); } - public E floor(E e) { return m.floorKey(e); } - public E ceiling(E e) { return m.ceilingKey(e); } - public E higher(E e) { return m.higherKey(e); } - public E first() { return m.firstKey(); } - public E last() { return m.lastKey(); } - public Comparator comparator() { return m.comparator(); } - public E pollFirst() { - Map.Entry e = m.pollFirstEntry(); - return (e == null) ? null : e.getKey(); - } - public E pollLast() { - Map.Entry e = m.pollLastEntry(); - return (e == null) ? null : e.getKey(); - } - public boolean remove(Object o) { - int oldSize = size(); - m.remove(o); - return size() != oldSize; - } - public NavigableSet7 subSet(E fromElement, boolean fromInclusive, - E toElement, boolean toInclusive) { - return new KeySet(m.subMap(fromElement, fromInclusive, - toElement, toInclusive)); - } - public NavigableSet7 headSet(E toElement, boolean inclusive) { - return new KeySet(m.headMap(toElement, inclusive)); - } - public NavigableSet7 tailSet(E fromElement, boolean inclusive) { - return new KeySet(m.tailMap(fromElement, inclusive)); - } - public SortedSet subSet(E fromElement, E toElement) { - return subSet(fromElement, true, toElement, false); - } - public SortedSet headSet(E toElement) { - return headSet(toElement, false); - } - public SortedSet tailSet(E fromElement) { - return tailSet(fromElement, true); - } - public NavigableSet7 descendingSet() { - return new KeySet(m.descendingMap()); - } - } - - /** - * Base class for TreeMap7 Iterators - */ - abstract class PrivateEntryIterator implements Iterator { - Entry next; - Entry lastReturned; - int expectedModCount; - - PrivateEntryIterator(Entry first) { - expectedModCount = modCount; - lastReturned = null; - next = first; - } - - public final boolean hasNext() { - return next != null; - } - - final Entry nextEntry() { - Entry e = next; - if (e == null) - throw new NoSuchElementException(); - if (modCount != expectedModCount) - throw new ConcurrentModificationException(); - next = successor(e); - lastReturned = e; - return e; - } - - final Entry prevEntry() { - Entry e = next; - if (e == null) - throw new NoSuchElementException(); - if (modCount != expectedModCount) - throw new ConcurrentModificationException(); - next = predecessor(e); - lastReturned = e; - return e; - } - - public void remove() { - if (lastReturned == null) - throw new IllegalStateException(); - if (modCount != expectedModCount) - throw new ConcurrentModificationException(); - // deleted entries are replaced by their successors - if (lastReturned.left != null && lastReturned.right != null) - next = lastReturned; - deleteEntry(lastReturned); - expectedModCount = modCount; - lastReturned = null; - } - } - - final class EntryIterator extends PrivateEntryIterator> { - EntryIterator(Entry first) { - super(first); - } - public Map.Entry next() { - return nextEntry(); - } - } - - final class ValueIterator extends PrivateEntryIterator { - ValueIterator(Entry first) { - super(first); - } - public V next() { - return nextEntry().value; - } - } - - final class KeyIterator extends PrivateEntryIterator { - KeyIterator(Entry first) { - super(first); - } - public K next() { - return nextEntry().key; - } - } - - final class DescendingKeyIterator extends PrivateEntryIterator { - DescendingKeyIterator(Entry first) { - super(first); - } - public K next() { - return prevEntry().key; - } - } - - // Little utilities - - /** - * Compares two keys using the correct comparison method for this TreeMap7. - */ - final int compare(Object k1, Object k2) { - return comparator==null ? ((Comparable)k1).compareTo((K)k2) - : comparator.compare((K)k1, (K)k2); - } - - /** - * Test two values for equality. Differs from o1.equals(o2) only in - * that it copes with {@code null} o1 properly. - */ - static final boolean valEquals(Object o1, Object o2) { - return (o1==null ? o2==null : o1.equals(o2)); - } - - /** - * Return SimpleImmutableEntry for entry, or null if null - */ - static Map.Entry exportEntry(TreeMap7.Entry e) { - return (e == null) ? null : - new AbstractMap7.SimpleImmutableEntry(e); - } - - /** - * Return key for entry, or null if null - */ - static K keyOrNull(TreeMap7.Entry e) { - return (e == null) ? null : e.key; - } - - /** - * Returns the key corresponding to the specified Entry. - * @throws NoSuchElementException if the Entry is null - */ - static K key(Entry e) { - if (e==null) - throw new NoSuchElementException(); - return e.key; - } - - - // SubMaps - - /** - * Dummy value serving as unmatchable fence key for unbounded - * SubMapIterators - */ - private static final Object UNBOUNDED = new Object(); - - /** - * @serial include - */ - abstract static class NavigableSubMap extends AbstractMap7 - implements NavigableMap7, java.io.Serializable { - /** - * The backing map. - */ - final TreeMap7 m; - - /** - * Endpoints are represented as triples (fromStart, lo, - * loInclusive) and (toEnd, hi, hiInclusive). If fromStart is - * true, then the low (absolute) bound is the start of the - * backing map, and the other values are ignored. Otherwise, - * if loInclusive is true, lo is the inclusive bound, else lo - * is the exclusive bound. Similarly for the upper bound. - */ - final K lo, hi; - final boolean fromStart, toEnd; - final boolean loInclusive, hiInclusive; - - NavigableSubMap(TreeMap7 m, - boolean fromStart, K lo, boolean loInclusive, - boolean toEnd, K hi, boolean hiInclusive) { - if (!fromStart && !toEnd) { - if (m.compare(lo, hi) > 0) - throw new IllegalArgumentException("fromKey > toKey"); - } else { - if (!fromStart) // type check - m.compare(lo, lo); - if (!toEnd) - m.compare(hi, hi); - } - - this.m = m; - this.fromStart = fromStart; - this.lo = lo; - this.loInclusive = loInclusive; - this.toEnd = toEnd; - this.hi = hi; - this.hiInclusive = hiInclusive; - } - - // internal utilities - - final boolean tooLow(Object key) { - if (!fromStart) { - int c = m.compare(key, lo); - if (c < 0 || (c == 0 && !loInclusive)) - return true; - } - return false; - } - - final boolean tooHigh(Object key) { - if (!toEnd) { - int c = m.compare(key, hi); - if (c > 0 || (c == 0 && !hiInclusive)) - return true; - } - return false; - } - - final boolean inRange(Object key) { - return !tooLow(key) && !tooHigh(key); - } - - final boolean inClosedRange(Object key) { - return (fromStart || m.compare(key, lo) >= 0) - && (toEnd || m.compare(hi, key) >= 0); - } - - final boolean inRange(Object key, boolean inclusive) { - return inclusive ? inRange(key) : inClosedRange(key); - } - - /* - * Absolute versions of relation operations. - * Subclasses map to these using like-named "sub" - * versions that invert senses for descending maps - */ - - final TreeMap7.Entry absLowest() { - TreeMap7.Entry e = - (fromStart ? m.getFirstEntry() : - (loInclusive ? m.getCeilingEntry(lo) : - m.getHigherEntry(lo))); - return (e == null || tooHigh(e.key)) ? null : e; - } - - final TreeMap7.Entry absHighest() { - TreeMap7.Entry e = - (toEnd ? m.getLastEntry() : - (hiInclusive ? m.getFloorEntry(hi) : - m.getLowerEntry(hi))); - return (e == null || tooLow(e.key)) ? null : e; - } - - final TreeMap7.Entry absCeiling(K key) { - if (tooLow(key)) - return absLowest(); - TreeMap7.Entry e = m.getCeilingEntry(key); - return (e == null || tooHigh(e.key)) ? null : e; - } - - final TreeMap7.Entry absHigher(K key) { - if (tooLow(key)) - return absLowest(); - TreeMap7.Entry e = m.getHigherEntry(key); - return (e == null || tooHigh(e.key)) ? null : e; - } - - final TreeMap7.Entry absFloor(K key) { - if (tooHigh(key)) - return absHighest(); - TreeMap7.Entry e = m.getFloorEntry(key); - return (e == null || tooLow(e.key)) ? null : e; - } - - final TreeMap7.Entry absLower(K key) { - if (tooHigh(key)) - return absHighest(); - TreeMap7.Entry e = m.getLowerEntry(key); - return (e == null || tooLow(e.key)) ? null : e; - } - - /** Returns the absolute high fence for ascending traversal */ - final TreeMap7.Entry absHighFence() { - return (toEnd ? null : (hiInclusive ? - m.getHigherEntry(hi) : - m.getCeilingEntry(hi))); - } - - /** Return the absolute low fence for descending traversal */ - final TreeMap7.Entry absLowFence() { - return (fromStart ? null : (loInclusive ? - m.getLowerEntry(lo) : - m.getFloorEntry(lo))); - } - - // Abstract methods defined in ascending vs descending classes - // These relay to the appropriate absolute versions - - abstract TreeMap7.Entry subLowest(); - abstract TreeMap7.Entry subHighest(); - abstract TreeMap7.Entry subCeiling(K key); - abstract TreeMap7.Entry subHigher(K key); - abstract TreeMap7.Entry subFloor(K key); - abstract TreeMap7.Entry subLower(K key); - - /** Returns ascending iterator from the perspective of this submap */ - abstract Iterator keyIterator(); - - /** Returns descending iterator from the perspective of this submap */ - abstract Iterator descendingKeyIterator(); - - // public methods - - public boolean isEmpty() { - return (fromStart && toEnd) ? m.isEmpty() : entrySet().isEmpty(); - } - - public int size() { - return (fromStart && toEnd) ? m.size() : entrySet().size(); - } - - public final boolean containsKey(Object key) { - return inRange(key) && m.containsKey(key); - } - - public final V put(K key, V value) { - if (!inRange(key)) - throw new IllegalArgumentException("key out of range"); - return m.put(key, value); - } - - public final V get(Object key) { - return !inRange(key) ? null : m.get(key); - } - - public final V remove(Object key) { - return !inRange(key) ? null : m.remove(key); - } - - public final Map.Entry ceilingEntry(K key) { - return exportEntry(subCeiling(key)); - } - - public final K ceilingKey(K key) { - return keyOrNull(subCeiling(key)); - } - - public final Map.Entry higherEntry(K key) { - return exportEntry(subHigher(key)); - } - - public final K higherKey(K key) { - return keyOrNull(subHigher(key)); - } - - public final Map.Entry floorEntry(K key) { - return exportEntry(subFloor(key)); - } - - public final K floorKey(K key) { - return keyOrNull(subFloor(key)); - } - - public final Map.Entry lowerEntry(K key) { - return exportEntry(subLower(key)); - } - - public final K lowerKey(K key) { - return keyOrNull(subLower(key)); - } - - public final K firstKey() { - return key(subLowest()); - } - - public final K lastKey() { - return key(subHighest()); - } - - public final Map.Entry firstEntry() { - return exportEntry(subLowest()); - } - - public final Map.Entry lastEntry() { - return exportEntry(subHighest()); - } - - public final Map.Entry pollFirstEntry() { - TreeMap7.Entry e = subLowest(); - Map.Entry result = exportEntry(e); - if (e != null) - m.deleteEntry(e); - return result; - } - - public final Map.Entry pollLastEntry() { - TreeMap7.Entry e = subHighest(); - Map.Entry result = exportEntry(e); - if (e != null) - m.deleteEntry(e); - return result; - } - - // Views - transient NavigableMap7 descendingMapView = null; - transient EntrySetView entrySetView = null; - transient KeySet navigableKeySetView = null; - - public final NavigableSet7 navigableKeySet() { - KeySet nksv = navigableKeySetView; - return (nksv != null) ? nksv : - (navigableKeySetView = new TreeMap7.KeySet(this)); - } - - public final Set keySet() { - return navigableKeySet(); - } - - public NavigableSet7 descendingKeySet() { - return descendingMap().navigableKeySet(); - } - - public final SortedMap subMap(K fromKey, K toKey) { - return subMap(fromKey, true, toKey, false); - } - - public final SortedMap headMap(K toKey) { - return headMap(toKey, false); - } - - public final SortedMap tailMap(K fromKey) { - return tailMap(fromKey, true); - } - - // View classes - - abstract class EntrySetView extends AbstractSet> { - private transient int size = -1, sizeModCount; - - public int size() { - if (fromStart && toEnd) - return m.size(); - if (size == -1 || sizeModCount != m.modCount) { - sizeModCount = m.modCount; - size = 0; - Iterator i = iterator(); - while (i.hasNext()) { - size++; - i.next(); - } - } - return size; - } - - public boolean isEmpty() { - TreeMap7.Entry n = absLowest(); - return n == null || tooHigh(n.key); - } - - public boolean contains(Object o) { - if (!(o instanceof Map.Entry)) - return false; - Map.Entry entry = (Map.Entry) o; - K key = entry.getKey(); - if (!inRange(key)) - return false; - TreeMap7.Entry node = m.getEntry(key); - return node != null && - valEquals(node.getValue(), entry.getValue()); - } - - public boolean remove(Object o) { - if (!(o instanceof Map.Entry)) - return false; - Map.Entry entry = (Map.Entry) o; - K key = entry.getKey(); - if (!inRange(key)) - return false; - TreeMap7.Entry node = m.getEntry(key); - if (node!=null && valEquals(node.getValue(), - entry.getValue())) { - m.deleteEntry(node); - return true; - } - return false; - } - } - - /** - * Iterators for SubMaps - */ - abstract class SubMapIterator implements Iterator { - TreeMap7.Entry lastReturned; - TreeMap7.Entry next; - final Object fenceKey; - int expectedModCount; - - SubMapIterator(TreeMap7.Entry first, - TreeMap7.Entry fence) { - expectedModCount = m.modCount; - lastReturned = null; - next = first; - fenceKey = fence == null ? UNBOUNDED : fence.key; - } - - public final boolean hasNext() { - return next != null && next.key != fenceKey; - } - - final TreeMap7.Entry nextEntry() { - TreeMap7.Entry e = next; - if (e == null || e.key == fenceKey) - throw new NoSuchElementException(); - if (m.modCount != expectedModCount) - throw new ConcurrentModificationException(); - next = successor(e); - lastReturned = e; - return e; - } - - final TreeMap7.Entry prevEntry() { - TreeMap7.Entry e = next; - if (e == null || e.key == fenceKey) - throw new NoSuchElementException(); - if (m.modCount != expectedModCount) - throw new ConcurrentModificationException(); - next = predecessor(e); - lastReturned = e; - return e; - } - - final void removeAscending() { - if (lastReturned == null) - throw new IllegalStateException(); - if (m.modCount != expectedModCount) - throw new ConcurrentModificationException(); - // deleted entries are replaced by their successors - if (lastReturned.left != null && lastReturned.right != null) - next = lastReturned; - m.deleteEntry(lastReturned); - lastReturned = null; - expectedModCount = m.modCount; - } - - final void removeDescending() { - if (lastReturned == null) - throw new IllegalStateException(); - if (m.modCount != expectedModCount) - throw new ConcurrentModificationException(); - m.deleteEntry(lastReturned); - lastReturned = null; - expectedModCount = m.modCount; - } - - } - - final class SubMapEntryIterator extends SubMapIterator> { - SubMapEntryIterator(TreeMap7.Entry first, - TreeMap7.Entry fence) { - super(first, fence); - } - public Map.Entry next() { - return nextEntry(); - } - public void remove() { - removeAscending(); - } - } - - final class SubMapKeyIterator extends SubMapIterator { - SubMapKeyIterator(TreeMap7.Entry first, - TreeMap7.Entry fence) { - super(first, fence); - } - public K next() { - return nextEntry().key; - } - public void remove() { - removeAscending(); - } - } - - final class DescendingSubMapEntryIterator extends SubMapIterator> { - DescendingSubMapEntryIterator(TreeMap7.Entry last, - TreeMap7.Entry fence) { - super(last, fence); - } - - public Map.Entry next() { - return prevEntry(); - } - public void remove() { - removeDescending(); - } - } - - final class DescendingSubMapKeyIterator extends SubMapIterator { - DescendingSubMapKeyIterator(TreeMap7.Entry last, - TreeMap7.Entry fence) { - super(last, fence); - } - public K next() { - return prevEntry().key; - } - public void remove() { - removeDescending(); - } - } - } - - /** - * @serial include - */ - static final class AscendingSubMap extends NavigableSubMap { - private static final long serialVersionUID = 912986545866124060L; - - AscendingSubMap(TreeMap7 m, - boolean fromStart, K lo, boolean loInclusive, - boolean toEnd, K hi, boolean hiInclusive) { - super(m, fromStart, lo, loInclusive, toEnd, hi, hiInclusive); - } - - public Comparator comparator() { - return m.comparator(); - } - - public NavigableMap7 subMap(K fromKey, boolean fromInclusive, - K toKey, boolean toInclusive) { - if (!inRange(fromKey, fromInclusive)) - throw new IllegalArgumentException("fromKey out of range"); - if (!inRange(toKey, toInclusive)) - throw new IllegalArgumentException("toKey out of range"); - return new AscendingSubMap(m, - false, fromKey, fromInclusive, - false, toKey, toInclusive); - } - - public NavigableMap7 headMap(K toKey, boolean inclusive) { - if (!inRange(toKey, inclusive)) - throw new IllegalArgumentException("toKey out of range"); - return new AscendingSubMap(m, - fromStart, lo, loInclusive, - false, toKey, inclusive); - } - - public NavigableMap7 tailMap(K fromKey, boolean inclusive) { - if (!inRange(fromKey, inclusive)) - throw new IllegalArgumentException("fromKey out of range"); - return new AscendingSubMap(m, - false, fromKey, inclusive, - toEnd, hi, hiInclusive); - } - - public NavigableMap7 descendingMap() { - NavigableMap7 mv = descendingMapView; - return (mv != null) ? mv : - (descendingMapView = - new DescendingSubMap(m, - fromStart, lo, loInclusive, - toEnd, hi, hiInclusive)); - } - - Iterator keyIterator() { - return new SubMapKeyIterator(absLowest(), absHighFence()); - } - - Iterator descendingKeyIterator() { - return new DescendingSubMapKeyIterator(absHighest(), absLowFence()); - } - - final class AscendingEntrySetView extends EntrySetView { - public Iterator> iterator() { - return new SubMapEntryIterator(absLowest(), absHighFence()); - } - } - - public Set> entrySet() { - EntrySetView es = entrySetView; - return (es != null) ? es : new AscendingEntrySetView(); - } - - TreeMap7.Entry subLowest() { return absLowest(); } - TreeMap7.Entry subHighest() { return absHighest(); } - TreeMap7.Entry subCeiling(K key) { return absCeiling(key); } - TreeMap7.Entry subHigher(K key) { return absHigher(key); } - TreeMap7.Entry subFloor(K key) { return absFloor(key); } - TreeMap7.Entry subLower(K key) { return absLower(key); } - } - - /** - * @serial include - */ - static final class DescendingSubMap extends NavigableSubMap { - private static final long serialVersionUID = 912986545866120460L; - DescendingSubMap(TreeMap7 m, - boolean fromStart, K lo, boolean loInclusive, - boolean toEnd, K hi, boolean hiInclusive) { - super(m, fromStart, lo, loInclusive, toEnd, hi, hiInclusive); - } - - private final Comparator reverseComparator = - Collections.reverseOrder(m.comparator); - - public Comparator comparator() { - return reverseComparator; - } - - public NavigableMap7 subMap(K fromKey, boolean fromInclusive, - K toKey, boolean toInclusive) { - if (!inRange(fromKey, fromInclusive)) - throw new IllegalArgumentException("fromKey out of range"); - if (!inRange(toKey, toInclusive)) - throw new IllegalArgumentException("toKey out of range"); - return new DescendingSubMap(m, - false, toKey, toInclusive, - false, fromKey, fromInclusive); - } - - public NavigableMap7 headMap(K toKey, boolean inclusive) { - if (!inRange(toKey, inclusive)) - throw new IllegalArgumentException("toKey out of range"); - return new DescendingSubMap(m, - false, toKey, inclusive, - toEnd, hi, hiInclusive); - } - - public NavigableMap7 tailMap(K fromKey, boolean inclusive) { - if (!inRange(fromKey, inclusive)) - throw new IllegalArgumentException("fromKey out of range"); - return new DescendingSubMap(m, - fromStart, lo, loInclusive, - false, fromKey, inclusive); - } - - public NavigableMap7 descendingMap() { - NavigableMap7 mv = descendingMapView; - return (mv != null) ? mv : - (descendingMapView = - new AscendingSubMap(m, - fromStart, lo, loInclusive, - toEnd, hi, hiInclusive)); - } - - Iterator keyIterator() { - return new DescendingSubMapKeyIterator(absHighest(), absLowFence()); - } - - Iterator descendingKeyIterator() { - return new SubMapKeyIterator(absLowest(), absHighFence()); - } - - final class DescendingEntrySetView extends EntrySetView { - public Iterator> iterator() { - return new DescendingSubMapEntryIterator(absHighest(), absLowFence()); - } - } - - public Set> entrySet() { - EntrySetView es = entrySetView; - return (es != null) ? es : new DescendingEntrySetView(); - } - - TreeMap7.Entry subLowest() { return absHighest(); } - TreeMap7.Entry subHighest() { return absLowest(); } - TreeMap7.Entry subCeiling(K key) { return absFloor(key); } - TreeMap7.Entry subHigher(K key) { return absLower(key); } - TreeMap7.Entry subFloor(K key) { return absCeiling(key); } - TreeMap7.Entry subLower(K key) { return absHigher(key); } - } - - /** - * This class exists solely for the sake of serialization - * compatibility with previous releases of TreeMap7 that did not - * support NavigableMap7. It translates an old-version SubMap into - * a new-version AscendingSubMap. This class is never otherwise - * used. - * - * @serial include - */ - private class SubMap extends AbstractMap7 - implements SortedMap, java.io.Serializable { - private static final long serialVersionUID = -6520786458950516097L; - private boolean fromStart = false, toEnd = false; - private K fromKey, toKey; - private Object readResolve() { - return new AscendingSubMap(TreeMap7.this, - fromStart, fromKey, true, - toEnd, toKey, false); - } - public Set> entrySet() { throw new InternalError(); } - public K lastKey() { throw new InternalError(); } - public K firstKey() { throw new InternalError(); } - public SortedMap subMap(K fromKey, K toKey) { throw new InternalError(); } - public SortedMap headMap(K toKey) { throw new InternalError(); } - public SortedMap tailMap(K fromKey) { throw new InternalError(); } - public Comparator comparator() { throw new InternalError(); } - } - - - // Red-black mechanics - - private static final boolean RED = false; - private static final boolean BLACK = true; - - /** - * Node in the Tree. Doubles as a means to pass key-value pairs back to - * user (see Map.Entry). - */ - - static final class Entry implements Map.Entry { - K key; - V value; - Entry left = null; - Entry right = null; - Entry parent; - boolean color = BLACK; - - /** - * Make a new cell with given key, value, and parent, and with - * {@code null} child links, and BLACK color. - */ - Entry(K key, V value, Entry parent) { - this.key = key; - this.value = value; - this.parent = parent; - } - - /** - * Returns the key. - * - * @return the key - */ - public K getKey() { - return key; - } - - /** - * Returns the value associated with the key. - * - * @return the value associated with the key - */ - public V getValue() { - return value; - } - - /** - * Replaces the value currently associated with the key with the given - * value. - * - * @return the value associated with the key before this method was - * called - */ - public V setValue(V value) { - V oldValue = this.value; - this.value = value; - return oldValue; - } - - public boolean equals(Object o) { - if (!(o instanceof Map.Entry)) - return false; - Map.Entry e = (Map.Entry)o; - - return valEquals(key,e.getKey()) && valEquals(value,e.getValue()); - } - - public int hashCode() { - int keyHash = (key==null ? 0 : key.hashCode()); - int valueHash = (value==null ? 0 : value.hashCode()); - return keyHash ^ valueHash; - } - - public String toString() { - return key + "=" + value; - } - } - - /** - * Returns the first Entry in the TreeMap7 (according to the TreeMap7's - * key-sort function). Returns null if the TreeMap7 is empty. - */ - final Entry getFirstEntry() { - Entry p = root; - if (p != null) - while (p.left != null) - p = p.left; - return p; - } - - /** - * Returns the last Entry in the TreeMap7 (according to the TreeMap7's - * key-sort function). Returns null if the TreeMap7 is empty. - */ - final Entry getLastEntry() { - Entry p = root; - if (p != null) - while (p.right != null) - p = p.right; - return p; - } - - /** - * Returns the successor of the specified Entry, or null if no such. - */ - static TreeMap7.Entry successor(Entry t) { - if (t == null) - return null; - else if (t.right != null) { - Entry p = t.right; - while (p.left != null) - p = p.left; - return p; - } else { - Entry p = t.parent; - Entry ch = t; - while (p != null && ch == p.right) { - ch = p; - p = p.parent; - } - return p; - } - } - - /** - * Returns the predecessor of the specified Entry, or null if no such. - */ - static Entry predecessor(Entry t) { - if (t == null) - return null; - else if (t.left != null) { - Entry p = t.left; - while (p.right != null) - p = p.right; - return p; - } else { - Entry p = t.parent; - Entry ch = t; - while (p != null && ch == p.left) { - ch = p; - p = p.parent; - } - return p; - } - } - - /** - * Balancing operations. - * - * Implementations of rebalancings during insertion and deletion are - * slightly different than the CLR version. Rather than using dummy - * nilnodes, we use a set of accessors that deal properly with null. They - * are used to avoid messiness surrounding nullness checks in the main - * algorithms. - */ - - private static boolean colorOf(Entry p) { - return (p == null ? BLACK : p.color); - } - - private static Entry parentOf(Entry p) { - return (p == null ? null: p.parent); - } - - private static void setColor(Entry p, boolean c) { - if (p != null) - p.color = c; - } - - private static Entry leftOf(Entry p) { - return (p == null) ? null: p.left; - } - - private static Entry rightOf(Entry p) { - return (p == null) ? null: p.right; - } - - /** From CLR */ - private void rotateLeft(Entry p) { - if (p != null) { - Entry r = p.right; - p.right = r.left; - if (r.left != null) - r.left.parent = p; - r.parent = p.parent; - if (p.parent == null) - root = r; - else if (p.parent.left == p) - p.parent.left = r; - else - p.parent.right = r; - r.left = p; - p.parent = r; - } - } - - /** From CLR */ - private void rotateRight(Entry p) { - if (p != null) { - Entry l = p.left; - p.left = l.right; - if (l.right != null) l.right.parent = p; - l.parent = p.parent; - if (p.parent == null) - root = l; - else if (p.parent.right == p) - p.parent.right = l; - else p.parent.left = l; - l.right = p; - p.parent = l; - } - } - - /** From CLR */ - private void fixAfterInsertion(Entry x) { - x.color = RED; - - while (x != null && x != root && x.parent.color == RED) { - if (parentOf(x) == leftOf(parentOf(parentOf(x)))) { - Entry y = rightOf(parentOf(parentOf(x))); - if (colorOf(y) == RED) { - setColor(parentOf(x), BLACK); - setColor(y, BLACK); - setColor(parentOf(parentOf(x)), RED); - x = parentOf(parentOf(x)); - } else { - if (x == rightOf(parentOf(x))) { - x = parentOf(x); - rotateLeft(x); - } - setColor(parentOf(x), BLACK); - setColor(parentOf(parentOf(x)), RED); - rotateRight(parentOf(parentOf(x))); - } - } else { - Entry y = leftOf(parentOf(parentOf(x))); - if (colorOf(y) == RED) { - setColor(parentOf(x), BLACK); - setColor(y, BLACK); - setColor(parentOf(parentOf(x)), RED); - x = parentOf(parentOf(x)); - } else { - if (x == leftOf(parentOf(x))) { - x = parentOf(x); - rotateRight(x); - } - setColor(parentOf(x), BLACK); - setColor(parentOf(parentOf(x)), RED); - rotateLeft(parentOf(parentOf(x))); - } - } - } - root.color = BLACK; - } - - /** - * Delete node p, and then rebalance the tree. - */ - private void deleteEntry(Entry p) { - modCount++; - size--; - - // If strictly internal, copy successor's element to p and then make p - // point to successor. - if (p.left != null && p.right != null) { - Entry s = successor(p); - p.key = s.key; - p.value = s.value; - p = s; - } // p has 2 children - - // Start fixup at replacement node, if it exists. - Entry replacement = (p.left != null ? p.left : p.right); - - if (replacement != null) { - // Link replacement to parent - replacement.parent = p.parent; - if (p.parent == null) - root = replacement; - else if (p == p.parent.left) - p.parent.left = replacement; - else - p.parent.right = replacement; - - // Null out links so they are OK to use by fixAfterDeletion. - p.left = p.right = p.parent = null; - - // Fix replacement - if (p.color == BLACK) - fixAfterDeletion(replacement); - } else if (p.parent == null) { // return if we are the only node. - root = null; - } else { // No children. Use self as phantom replacement and unlink. - if (p.color == BLACK) - fixAfterDeletion(p); - - if (p.parent != null) { - if (p == p.parent.left) - p.parent.left = null; - else if (p == p.parent.right) - p.parent.right = null; - p.parent = null; - } - } - } - - /** From CLR */ - private void fixAfterDeletion(Entry x) { - while (x != root && colorOf(x) == BLACK) { - if (x == leftOf(parentOf(x))) { - Entry sib = rightOf(parentOf(x)); - - if (colorOf(sib) == RED) { - setColor(sib, BLACK); - setColor(parentOf(x), RED); - rotateLeft(parentOf(x)); - sib = rightOf(parentOf(x)); - } - - if (colorOf(leftOf(sib)) == BLACK && - colorOf(rightOf(sib)) == BLACK) { - setColor(sib, RED); - x = parentOf(x); - } else { - if (colorOf(rightOf(sib)) == BLACK) { - setColor(leftOf(sib), BLACK); - setColor(sib, RED); - rotateRight(sib); - sib = rightOf(parentOf(x)); - } - setColor(sib, colorOf(parentOf(x))); - setColor(parentOf(x), BLACK); - setColor(rightOf(sib), BLACK); - rotateLeft(parentOf(x)); - x = root; - } - } else { // symmetric - Entry sib = leftOf(parentOf(x)); - - if (colorOf(sib) == RED) { - setColor(sib, BLACK); - setColor(parentOf(x), RED); - rotateRight(parentOf(x)); - sib = leftOf(parentOf(x)); - } - - if (colorOf(rightOf(sib)) == BLACK && - colorOf(leftOf(sib)) == BLACK) { - setColor(sib, RED); - x = parentOf(x); - } else { - if (colorOf(leftOf(sib)) == BLACK) { - setColor(rightOf(sib), BLACK); - setColor(sib, RED); - rotateLeft(sib); - sib = leftOf(parentOf(x)); - } - setColor(sib, colorOf(parentOf(x))); - setColor(parentOf(x), BLACK); - setColor(leftOf(sib), BLACK); - rotateRight(parentOf(x)); - x = root; - } - } - } - - setColor(x, BLACK); - } - - private static final long serialVersionUID = 919286545866124006L; - - /** - * Save the state of the {@code TreeMap7} instance to a stream (i.e., - * serialize it). - * - * @serialData The size of the TreeMap7 (the number of key-value - * mappings) is emitted (int), followed by the key (Object) - * and value (Object) for each key-value mapping represented - * by the TreeMap7. The key-value mappings are emitted in - * key-order (as determined by the TreeMap7's Comparator, - * or by the keys' natural ordering if the TreeMap7 has no - * Comparator). - */ - private void writeObject(java.io.ObjectOutputStream s) - throws java.io.IOException { - // Write out the Comparator and any hidden stuff - s.defaultWriteObject(); - - // Write out size (number of Mappings) - s.writeInt(size); - - // Write out keys and values (alternating) - for (Iterator> i = entrySet().iterator(); i.hasNext(); ) { - Map.Entry e = i.next(); - s.writeObject(e.getKey()); - s.writeObject(e.getValue()); - } - } - - /** - * Reconstitute the {@code TreeMap7} instance from a stream (i.e., - * deserialize it). - */ - private void readObject(final java.io.ObjectInputStream s) - throws java.io.IOException, ClassNotFoundException { - // Read in the Comparator and any hidden stuff - s.defaultReadObject(); - - // Read in size - int size = s.readInt(); - - buildFromSorted(size, null, s, null); - } - - /** Intended to be called only from TreeSet.readObject */ - void readTreeSet(int size, java.io.ObjectInputStream s, V defaultVal) - throws java.io.IOException, ClassNotFoundException { - buildFromSorted(size, null, s, defaultVal); - } - - /** Intended to be called only from TreeSet.addAll */ - void addAllForTreeSet(SortedSet set, V defaultVal) { - try { - buildFromSorted(set.size(), set.iterator(), null, defaultVal); - } catch (java.io.IOException cannotHappen) { - } catch (ClassNotFoundException cannotHappen) { - } - } - - - /** - * Linear time tree building algorithm from sorted data. Can accept keys - * and/or values from iterator or stream. This leads to too many - * parameters, but seems better than alternatives. The four formats - * that this method accepts are: - * - * 1) An iterator of Map.Entries. (it != null, defaultVal == null). - * 2) An iterator of keys. (it != null, defaultVal != null). - * 3) A stream of alternating serialized keys and values. - * (it == null, defaultVal == null). - * 4) A stream of serialized keys. (it == null, defaultVal != null). - * - * It is assumed that the comparator of the TreeMap7 is already set prior - * to calling this method. - * - * @param size the number of keys (or key-value pairs) to be read from - * the iterator or stream - * @param it If non-null, new entries are created from entries - * or keys read from this iterator. - * @param str If non-null, new entries are created from keys and - * possibly values read from this stream in serialized form. - * Exactly one of it and str should be non-null. - * @param defaultVal if non-null, this default value is used for - * each value in the map. If null, each value is read from - * iterator or stream, as described above. - * @throws IOException propagated from stream reads. This cannot - * occur if str is null. - * @throws ClassNotFoundException propagated from readObject. - * This cannot occur if str is null. - */ - private void buildFromSorted(int size, Iterator it, - java.io.ObjectInputStream str, - V defaultVal) - throws java.io.IOException, ClassNotFoundException { - this.size = size; - root = buildFromSorted(0, 0, size-1, computeRedLevel(size), - it, str, defaultVal); - } - - /** - * Recursive "helper method" that does the real work of the - * previous method. Identically named parameters have - * identical definitions. Additional parameters are documented below. - * It is assumed that the comparator and size fields of the TreeMap7 are - * already set prior to calling this method. (It ignores both fields.) - * - * @param level the current level of tree. Initial call should be 0. - * @param lo the first element index of this subtree. Initial should be 0. - * @param hi the last element index of this subtree. Initial should be - * size-1. - * @param redLevel the level at which nodes should be red. - * Must be equal to computeRedLevel for tree of this size. - */ - private final Entry buildFromSorted(int level, int lo, int hi, - int redLevel, - Iterator it, - java.io.ObjectInputStream str, - V defaultVal) - throws java.io.IOException, ClassNotFoundException { - /* - * Strategy: The root is the middlemost element. To get to it, we - * have to first recursively construct the entire left subtree, - * so as to grab all of its elements. We can then proceed with right - * subtree. - * - * The lo and hi arguments are the minimum and maximum - * indices to pull out of the iterator or stream for current subtree. - * They are not actually indexed, we just proceed sequentially, - * ensuring that items are extracted in corresponding order. - */ - - if (hi < lo) return null; - - int mid = (lo + hi) >>> 1; - - Entry left = null; - if (lo < mid) - left = buildFromSorted(level+1, lo, mid - 1, redLevel, - it, str, defaultVal); - - // extract key and/or value from iterator or stream - K key; - V value; - if (it != null) { - if (defaultVal==null) { - Map.Entry entry = (Map.Entry)it.next(); - key = entry.getKey(); - value = entry.getValue(); - } else { - key = (K)it.next(); - value = defaultVal; - } - } else { // use stream - key = (K) str.readObject(); - value = (defaultVal != null ? defaultVal : (V) str.readObject()); - } - - Entry middle = new Entry(key, value, null); - - // color nodes in non-full bottommost level red - if (level == redLevel) - middle.color = RED; - - if (left != null) { - middle.left = left; - left.parent = middle; - } - - if (mid < hi) { - Entry right = buildFromSorted(level+1, mid+1, hi, redLevel, - it, str, defaultVal); - middle.right = right; - right.parent = middle; - } - - return middle; - } - - /** - * Find the level down to which to assign all nodes BLACK. This is the - * last `full' level of the complete binary tree produced by - * buildTree. The remaining nodes are colored RED. (This makes a `nice' - * set of color assignments wrt future insertions.) This level number is - * computed by finding the number of splits needed to reach the zeroeth - * node. (The answer is ~lg(N), but in any case must be computed by same - * quick O(lg(N)) loop.) - */ - private static int computeRedLevel(int sz) { - int level = 0; - for (int m = sz - 1; m >= 0; m = m / 2 - 1) - level++; - return level; - } -} \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/util/java7_util/TreeSet7.java b/src/ooxml/java/org/apache/poi/util/java7_util/TreeSet7.java deleted file mode 100644 index 3369b9c1f..000000000 --- a/src/ooxml/java/org/apache/poi/util/java7_util/TreeSet7.java +++ /dev/null @@ -1,554 +0,0 @@ -/* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.apache.poi.util.java7_util; - -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.ConcurrentModificationException; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeMap; - -/** - * A {@link NavigableSet7} implementation based on a {@link TreeMap}. - * The elements are ordered using their {@linkplain Comparable natural - * ordering}, or by a {@link Comparator} provided at set creation - * time, depending on which constructor is used. - * - *

This implementation provides guaranteed log(n) time cost for the basic - * operations ({@code add}, {@code remove} and {@code contains}). - * - *

Note that the ordering maintained by a set (whether or not an explicit - * comparator is provided) must be consistent with equals if it is to - * correctly implement the {@code Set} interface. (See {@code Comparable} - * or {@code Comparator} for a precise definition of consistent with - * equals.) This is so because the {@code Set} interface is defined in - * terms of the {@code equals} operation, but a {@code TreeSet7} instance - * performs all element comparisons using its {@code compareTo} (or - * {@code compare}) method, so two elements that are deemed equal by this method - * are, from the standpoint of the set, equal. The behavior of a set - * is well-defined even if its ordering is inconsistent with equals; it - * just fails to obey the general contract of the {@code Set} interface. - * - *

Note that this implementation is not synchronized. - * If multiple threads access a tree set concurrently, and at least one - * of the threads modifies the set, it must be synchronized - * externally. This is typically accomplished by synchronizing on some - * object that naturally encapsulates the set. - * If no such object exists, the set should be "wrapped" using the - * {@link Collections#synchronizedSortedSet Collections.synchronizedSortedSet} - * method. This is best done at creation time, to prevent accidental - * unsynchronized access to the set:

- *   SortedSet s = Collections.synchronizedSortedSet(new TreeSet7(...));
- * - *

The iterators returned by this class's {@code iterator} method are - * fail-fast: if the set is modified at any time after the iterator is - * created, in any way except through the iterator's own {@code remove} - * method, the iterator will throw a {@link ConcurrentModificationException}. - * Thus, in the face of concurrent modification, the iterator fails quickly - * and cleanly, rather than risking arbitrary, non-deterministic behavior at - * an undetermined time in the future. - * - *

Note that the fail-fast behavior of an iterator cannot be guaranteed - * as it is, generally speaking, impossible to make any hard guarantees in the - * presence of unsynchronized concurrent modification. Fail-fast iterators - * throw {@code ConcurrentModificationException} on a best-effort basis. - * Therefore, it would be wrong to write a program that depended on this - * exception for its correctness: the fail-fast behavior of iterators - * should be used only to detect bugs. - * - *

This class is a member of the - * - * Java Collections Framework. - * - * @param the type of elements maintained by this set - * - * @author Josh Bloch - * @see Collection - * @see Set - * @see HashSet - * @see Comparable - * @see Comparator - * @see TreeMap - * @since 1.2 - */ - -public class TreeSet7 extends AbstractSet7 - implements NavigableSet7, Cloneable, java.io.Serializable -{ - /** - * The backing map. - */ - private transient NavigableMap7 m; - - // Dummy value to associate with an Object in the backing Map - private static final Object PRESENT = new Object(); - - /** - * Constructs a set backed by the specified navigable map. - */ - TreeSet7(NavigableMap7 m) { - this.m = m; - } - - /** - * Constructs a new, empty tree set, sorted according to the - * natural ordering of its elements. All elements inserted into - * the set must implement the {@link Comparable} interface. - * Furthermore, all such elements must be mutually - * comparable: {@code e1.compareTo(e2)} must not throw a - * {@code ClassCastException} for any elements {@code e1} and - * {@code e2} in the set. If the user attempts to add an element - * to the set that violates this constraint (for example, the user - * attempts to add a string element to a set whose elements are - * integers), the {@code add} call will throw a - * {@code ClassCastException}. - */ - public TreeSet7() { - this(new TreeMap7()); - } - - /** - * Constructs a new, empty tree set, sorted according to the specified - * comparator. All elements inserted into the set must be mutually - * comparable by the specified comparator: {@code comparator.compare(e1, - * e2)} must not throw a {@code ClassCastException} for any elements - * {@code e1} and {@code e2} in the set. If the user attempts to add - * an element to the set that violates this constraint, the - * {@code add} call will throw a {@code ClassCastException}. - * - * @param comparator the comparator that will be used to order this set. - * If {@code null}, the {@linkplain Comparable natural - * ordering} of the elements will be used. - */ - public TreeSet7(Comparator comparator) { - this(new TreeMap7(comparator)); - } - - /** - * Constructs a new tree set containing the elements in the specified - * collection, sorted according to the natural ordering of its - * elements. All elements inserted into the set must implement the - * {@link Comparable} interface. Furthermore, all such elements must be - * mutually comparable: {@code e1.compareTo(e2)} must not throw a - * {@code ClassCastException} for any elements {@code e1} and - * {@code e2} in the set. - * - * @param c collection whose elements will comprise the new set - * @throws ClassCastException if the elements in {@code c} are - * not {@link Comparable}, or are not mutually comparable - * @throws NullPointerException if the specified collection is null - */ - public TreeSet7(Collection c) { - this(); - addAll(c); - } - - /** - * Constructs a new tree set containing the same elements and - * using the same ordering as the specified sorted set. - * - * @param s sorted set whose elements will comprise the new set - * @throws NullPointerException if the specified sorted set is null - */ - public TreeSet7(SortedSet s) { - this(s.comparator()); - addAll(s); - } - - /** - * Returns an iterator over the elements in this set in ascending order. - * - * @return an iterator over the elements in this set in ascending order - */ - public Iterator iterator() { - return m.navigableKeySet().iterator(); - } - - /** - * Returns an iterator over the elements in this set in descending order. - * - * @return an iterator over the elements in this set in descending order - * @since 1.6 - */ - public Iterator descendingIterator() { - return m.descendingKeySet().iterator(); - } - - /** - * @since 1.6 - */ - public NavigableSet7 descendingSet() { - return new TreeSet7(m.descendingMap()); - } - - /** - * Returns the number of elements in this set (its cardinality). - * - * @return the number of elements in this set (its cardinality) - */ - public int size() { - return m.size(); - } - - /** - * Returns {@code true} if this set contains no elements. - * - * @return {@code true} if this set contains no elements - */ - public boolean isEmpty() { - return m.isEmpty(); - } - - /** - * Returns {@code true} if this set contains the specified element. - * More formally, returns {@code true} if and only if this set - * contains an element {@code e} such that - * (o==null ? e==null : o.equals(e)). - * - * @param o object to be checked for containment in this set - * @return {@code true} if this set contains the specified element - * @throws ClassCastException if the specified object cannot be compared - * with the elements currently in the set - * @throws NullPointerException if the specified element is null - * and this set uses natural ordering, or its comparator - * does not permit null elements - */ - public boolean contains(Object o) { - return m.containsKey(o); - } - - /** - * Adds the specified element to this set if it is not already present. - * More formally, adds the specified element {@code e} to this set if - * the set contains no element {@code e2} such that - * (e==null ? e2==null : e.equals(e2)). - * If this set already contains the element, the call leaves the set - * unchanged and returns {@code false}. - * - * @param e element to be added to this set - * @return {@code true} if this set did not already contain the specified - * element - * @throws ClassCastException if the specified object cannot be compared - * with the elements currently in this set - * @throws NullPointerException if the specified element is null - * and this set uses natural ordering, or its comparator - * does not permit null elements - */ - public boolean add(E e) { - return m.put(e, PRESENT)==null; - } - - /** - * Removes the specified element from this set if it is present. - * More formally, removes an element {@code e} such that - * (o==null ? e==null : o.equals(e)), - * if this set contains such an element. Returns {@code true} if - * this set contained the element (or equivalently, if this set - * changed as a result of the call). (This set will not contain the - * element once the call returns.) - * - * @param o object to be removed from this set, if present - * @return {@code true} if this set contained the specified element - * @throws ClassCastException if the specified object cannot be compared - * with the elements currently in this set - * @throws NullPointerException if the specified element is null - * and this set uses natural ordering, or its comparator - * does not permit null elements - */ - public boolean remove(Object o) { - return m.remove(o)==PRESENT; - } - - /** - * Removes all of the elements from this set. - * The set will be empty after this call returns. - */ - public void clear() { - m.clear(); - } - - /** - * Adds all of the elements in the specified collection to this set. - * - * @param c collection containing elements to be added to this set - * @return {@code true} if this set changed as a result of the call - * @throws ClassCastException if the elements provided cannot be compared - * with the elements currently in the set - * @throws NullPointerException if the specified collection is null or - * if any element is null and this set uses natural ordering, or - * its comparator does not permit null elements - */ - public boolean addAll(Collection c) { - // Use linear-time version if applicable - if (m.size()==0 && c.size() > 0 && - c instanceof SortedSet && - m instanceof TreeMap7) { - SortedSet set = (SortedSet) c; - TreeMap7 map = (TreeMap7) m; - @SuppressWarnings("unchecked") - Comparator cc = (Comparator) set.comparator(); - Comparator mc = map.comparator(); - if (cc==mc || (cc != null && cc.equals(mc))) { - map.addAllForTreeSet(set, PRESENT); - return true; - } - } - return super.addAll(c); - } - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if {@code fromElement} or {@code toElement} - * is null and this set uses natural ordering, or its comparator - * does not permit null elements - * @throws IllegalArgumentException {@inheritDoc} - * @since 1.6 - */ - public NavigableSet7 subSet(E fromElement, boolean fromInclusive, - E toElement, boolean toInclusive) { - return new TreeSet7(m.subMap(fromElement, fromInclusive, - toElement, toInclusive)); - } - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if {@code toElement} is null and - * this set uses natural ordering, or its comparator does - * not permit null elements - * @throws IllegalArgumentException {@inheritDoc} - * @since 1.6 - */ - public NavigableSet7 headSet(E toElement, boolean inclusive) { - return new TreeSet7(m.headMap(toElement, inclusive)); - } - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if {@code fromElement} is null and - * this set uses natural ordering, or its comparator does - * not permit null elements - * @throws IllegalArgumentException {@inheritDoc} - * @since 1.6 - */ - public NavigableSet7 tailSet(E fromElement, boolean inclusive) { - return new TreeSet7(m.tailMap(fromElement, inclusive)); - } - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if {@code fromElement} or - * {@code toElement} is null and this set uses natural ordering, - * or its comparator does not permit null elements - * @throws IllegalArgumentException {@inheritDoc} - */ - public SortedSet subSet(E fromElement, E toElement) { - return subSet(fromElement, true, toElement, false); - } - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if {@code toElement} is null - * and this set uses natural ordering, or its comparator does - * not permit null elements - * @throws IllegalArgumentException {@inheritDoc} - */ - public SortedSet headSet(E toElement) { - return headSet(toElement, false); - } - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if {@code fromElement} is null - * and this set uses natural ordering, or its comparator does - * not permit null elements - * @throws IllegalArgumentException {@inheritDoc} - */ - public SortedSet tailSet(E fromElement) { - return tailSet(fromElement, true); - } - - public Comparator comparator() { - return m.comparator(); - } - - /** - * @throws NoSuchElementException {@inheritDoc} - */ - public E first() { - return m.firstKey(); - } - - /** - * @throws NoSuchElementException {@inheritDoc} - */ - public E last() { - return m.lastKey(); - } - - // NavigableSet API methods - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if the specified element is null - * and this set uses natural ordering, or its comparator - * does not permit null elements - * @since 1.6 - */ - public E lower(E e) { - return m.lowerKey(e); - } - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if the specified element is null - * and this set uses natural ordering, or its comparator - * does not permit null elements - * @since 1.6 - */ - public E floor(E e) { - return m.floorKey(e); - } - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if the specified element is null - * and this set uses natural ordering, or its comparator - * does not permit null elements - * @since 1.6 - */ - public E ceiling(E e) { - return m.ceilingKey(e); - } - - /** - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException if the specified element is null - * and this set uses natural ordering, or its comparator - * does not permit null elements - * @since 1.6 - */ - public E higher(E e) { - return m.higherKey(e); - } - - /** - * @since 1.6 - */ - public E pollFirst() { - Map.Entry e = m.pollFirstEntry(); - return (e == null) ? null : e.getKey(); - } - - /** - * @since 1.6 - */ - public E pollLast() { - Map.Entry e = m.pollLastEntry(); - return (e == null) ? null : e.getKey(); - } - - /** - * Returns a shallow copy of this {@code TreeSet7} instance. (The elements - * themselves are not cloned.) - * - * @return a shallow copy of this set - */ - @SuppressWarnings("unchecked") - public Object clone() { - TreeSet7 clone = null; - try { - clone = (TreeSet7) super.clone(); - } catch (CloneNotSupportedException e) { - throw new InternalError(); - } - - clone.m = new TreeMap7(m); - return clone; - } - - /** - * Save the state of the {@code TreeSet7} instance to a stream (that is, - * serialize it). - * - * @serialData Emits the comparator used to order this set, or - * {@code null} if it obeys its elements' natural ordering - * (Object), followed by the size of the set (the number of - * elements it contains) (int), followed by all of its - * elements (each an Object) in order (as determined by the - * set's Comparator, or by the elements' natural ordering if - * the set has no Comparator). - */ - private void writeObject(java.io.ObjectOutputStream s) - throws java.io.IOException { - // Write out any hidden stuff - s.defaultWriteObject(); - - // Write out Comparator - s.writeObject(m.comparator()); - - // Write out size - s.writeInt(m.size()); - - // Write out all elements in the proper order. - for (E e : m.keySet()) - s.writeObject(e); - } - - /** - * Reconstitute the {@code TreeSet7} instance from a stream (that is, - * deserialize it). - */ - private void readObject(java.io.ObjectInputStream s) - throws java.io.IOException, ClassNotFoundException { - // Read in any hidden stuff - s.defaultReadObject(); - - // Read in Comparator - @SuppressWarnings("unchecked") - Comparator c = (Comparator) s.readObject(); - - // Create backing TreeMap - TreeMap7 tm; - if (c==null) - tm = new TreeMap7(); - else - tm = new TreeMap7(c); - m = tm; - - // Read in size - int size = s.readInt(); - - tm.readTreeSet(size, s, PRESENT); - } - - private static final long serialVersionUID = -2479143000061671589L; -} \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/ColumnHelper.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/ColumnHelper.java index 4b2bdc423..e8751ef89 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/ColumnHelper.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/ColumnHelper.java @@ -25,9 +25,9 @@ import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Set; +import java.util.TreeSet; import org.apache.poi.ss.usermodel.CellStyle; -import org.apache.poi.util.java7_util.TreeSet7; import org.apache.poi.xssf.util.CTColComparator; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols; @@ -95,7 +95,7 @@ public class ColumnHelper { */ private void sweepCleanColumns(CTCols cols, CTCol[] flattenedColsArray, CTCol overrideColumn) { List flattenedCols = new ArrayList(Arrays.asList(flattenedColsArray)); - TreeSet7 currentElements = new TreeSet7(new CTColByMaxComparator()); + TreeSet currentElements = new TreeSet(new CTColByMaxComparator()); ListIterator flIter = flattenedCols.listIterator(); CTCol haveOverrideColumn = null; long lastMaxIndex = 0; From bd3cd2243edd852a90abeee3a4bc5cb790dffef2 Mon Sep 17 00:00:00 2001 From: Andreas Beeker Date: Sun, 26 Jan 2014 16:26:59 +0000 Subject: [PATCH 11/11] TreeSet without JDK 6 method usages git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1561511 13f79535-47bb-0310-9956-ffa450edef68 --- .../xssf/usermodel/helpers/ColumnHelper.java | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/ColumnHelper.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/ColumnHelper.java index e8751ef89..4f64c7a4d 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/ColumnHelper.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/ColumnHelper.java @@ -123,15 +123,31 @@ public class ColumnHelper { if (col.equals(overrideColumn)) haveOverrideColumn = overrideColumn; while (currentIndex <= nextIndex && !currentElements.isEmpty()) { Set currentIndexElements = new HashSet(); - CTCol currentElem = currentElements.first(); - long currentElemIndex = currentElem.getMax(); - currentIndexElements.add(currentElem); - while (currentElements.higher(currentElem) != null && currentElements.higher(currentElem).getMax() == currentElemIndex) { - currentElem = currentElements.higher(currentElem); + long currentElemIndex; + + { + // narrow scope of currentElem + CTCol currentElem = currentElements.first(); + currentElemIndex = currentElem.getMax(); currentIndexElements.add(currentElem); - if (col.getMax() > currentMax) currentMax = col.getMax(); - if (col.equals(overrideColumn)) haveOverrideColumn = overrideColumn; + + for (CTCol cc : currentElements.tailSet(currentElem)) { + if (cc == null || cc.getMax() == currentElemIndex) break; + currentIndexElements.add(cc); + if (col.getMax() > currentMax) currentMax = col.getMax(); + if (col.equals(overrideColumn)) haveOverrideColumn = overrideColumn; + } + + // JDK 6 code + // while (currentElements.higher(currentElem) != null && currentElements.higher(currentElem).getMax() == currentElemIndex) { + // currentElem = currentElements.higher(currentElem); + // currentIndexElements.add(currentElem); + // if (col.getMax() > currentMax) currentMax = col.getMax(); + // if (col.equals(overrideColumn)) haveOverrideColumn = overrideColumn; + // } } + + if (currentElemIndex < nextIndex || !flIter.hasNext()) { insertCol(cols, currentIndex, currentElemIndex, currentElements.toArray(new CTCol[]{}), true, haveOverrideColumn); if (flIter.hasNext()) {