Introduce LoaderOptions to be able to specify configuration while loading
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 5a719b6..bf5cc46 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -7,6 +7,9 @@
 	</properties>

 	<body>

           <release version="1.8-SNAPSHOT" date="in Mercurial" description="Performance improvement">

+            <action dev="py4fun" type="update" issue="79">

+                Introduce LoaderOptions to be able to specify configuration while loading (2010-09-03)

+            </action>

             <action dev="py4fun" type="fix" issue="81">

                 Representer.representJavaBeanProperty() is given the wrong tag. Instead of the property tag, 

                 the tag for the JavaBean itself is provided. (2010-09-01)

diff --git a/src/main/java/org/yaml/snakeyaml/LoaderOptions.java b/src/main/java/org/yaml/snakeyaml/LoaderOptions.java
new file mode 100644
index 0000000..c19c7b8
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/LoaderOptions.java
@@ -0,0 +1,67 @@
+/**
+ * Copyright (c) 2008-2010, http://code.google.com/p/snakeyaml/
+ *
+ * Licensed 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.yaml.snakeyaml;
+
+public class LoaderOptions {
+    private final Mode mode;
+
+    public enum Mode {
+        /**
+         * Store context with a Mark to have a better error message. Loader
+         * works 40% slower and it consumes much more memory (default=false)
+         */
+        CONTEXT_MARK(1),
+        /**
+         * Disable implicit types when JavaBean is loaded (default=true). When
+         * this is present then USE_IMPLICIT_TYPES is ignored.
+         */
+        DYNAMIC_IMPLICIT_TYPES(2),
+        /**
+         * When DYNAMIC_IMPLICIT_TYPES is 'false' defines whether to apply the
+         * regular expressions. When implicit types are not used all the scalars
+         * are Strings. Enable this when JavaBean has a property which is a
+         * generic collections like Map<String, Integer>
+         */
+        USE_IMPLICIT_TYPES(4),
+        /**
+         * Enable compact format for JavaBeans
+         */
+        COMPACT_FORMAT(8);
+
+        private final int mask;
+
+        private Mode(int mask) {
+            this.mask = mask;
+        }
+
+        public boolean hasMode(Mode mode) {
+            return (mode.mask & this.mask) == mode.mask;
+        }
+    }
+
+    public LoaderOptions(Mode mode) {
+        this.mode = mode;
+    }
+
+    public LoaderOptions() {
+        this(Mode.DYNAMIC_IMPLICIT_TYPES);
+    }
+
+    public boolean hasMode(Mode mode) {
+        return this.mode.hasMode(mode);
+    }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/Yaml.java b/src/main/java/org/yaml/snakeyaml/Yaml.java
index de69427..f500894 100644
--- a/src/main/java/org/yaml/snakeyaml/Yaml.java
+++ b/src/main/java/org/yaml/snakeyaml/Yaml.java
@@ -52,7 +52,7 @@
     protected BaseConstructor constructor;

     protected Representer representer;

     protected DumperOptions options;

-    protected boolean attachBufferToMark = true;

+    protected LoaderOptions loaderOptions = new LoaderOptions();

 

     /**

      * Create Yaml instance. It is safe to create a few instances and use them

@@ -62,6 +62,11 @@
         this(new Constructor(), new Representer(), new DumperOptions(), new Resolver());

     }

 

+    public Yaml(LoaderOptions loaderOptions) {

+        this(new Constructor(), loaderOptions, new Representer(), new DumperOptions(),

+                new Resolver());

+    }

+

     /**

      * Create Yaml instance.

      * 

@@ -150,12 +155,33 @@
      */

     public Yaml(BaseConstructor constructor, Representer representer, DumperOptions options,

             Resolver resolver) {

+        this(constructor, new LoaderOptions(), representer, options, resolver);

+    }

+

+    /**

+     * Create Yaml instance. It is safe to create a few instances and use them

+     * in different Threads.

+     * 

+     * @param constructor

+     *            BaseConstructor to construct incoming documents

+     * @param loaderOptions

+     *            LoaderOptions to control construction process

+     * @param representer

+     *            Representer to emit outgoing objects

+     * @param options

+     *            DumperOptions to configure outgoing objects

+     * @param resolver

+     *            Resolver to detect implicit type

+     */

+    public Yaml(BaseConstructor constructor, LoaderOptions loaderOptions, Representer representer,

+            DumperOptions options, Resolver resolver) {

         if (!constructor.isExplicitPropertyUtils()) {

             constructor.setPropertyUtils(representer.getPropertyUtils());

         } else if (!representer.isExplicitPropertyUtils()) {

             representer.setPropertyUtils(constructor.getPropertyUtils());

         }

         this.constructor = constructor;

+        this.loaderOptions = loaderOptions;

         representer.setDefaultFlowStyle(options.getDefaultFlowStyle());

         representer.setDefaultScalarStyle(options.getDefaultScalarStyle());

         representer.getPropertyUtils().setAllowReadOnlyProperties(

@@ -260,8 +286,8 @@
      * @return parsed object

      */

     public Object load(Reader io) {

-        Composer composer = new Composer(new ParserImpl(new StreamReader(io, attachBufferToMark)),

-                resolver);

+        Composer composer = new Composer(new ParserImpl(new StreamReader(io, loaderOptions

+                .hasMode(LoaderOptions.Mode.CONTEXT_MARK))), resolver);

         constructor.setComposer(composer);

         return constructor.getSingleData();

     }

@@ -276,8 +302,8 @@
      *         sequence

      */

     public Iterable<Object> loadAll(Reader yaml) {

-        Composer composer = new Composer(

-                new ParserImpl(new StreamReader(yaml, attachBufferToMark)), resolver);

+        Composer composer = new Composer(new ParserImpl(new StreamReader(yaml, loaderOptions

+                .hasMode(LoaderOptions.Mode.CONTEXT_MARK))), resolver);

         constructor.setComposer(composer);

         Iterator<Object> result = new Iterator<Object>() {

             public boolean hasNext() {

@@ -343,8 +369,8 @@
      * @return parsed root Node for the specified YAML document

      */

     public Node compose(Reader yaml) {

-        Composer composer = new Composer(

-                new ParserImpl(new StreamReader(yaml, attachBufferToMark)), resolver);

+        Composer composer = new Composer(new ParserImpl(new StreamReader(yaml, loaderOptions

+                .hasMode(LoaderOptions.Mode.CONTEXT_MARK))), resolver);

         constructor.setComposer(composer);

         return composer.getSingleNode();

     }

@@ -358,8 +384,8 @@
      * @return parsed root Nodes for all the specified YAML documents

      */

     public Iterable<Node> composeAll(Reader yaml) {

-        final Composer composer = new Composer(new ParserImpl(new StreamReader(yaml,

-                attachBufferToMark)), resolver);

+        final Composer composer = new Composer(new ParserImpl(new StreamReader(yaml, loaderOptions

+                .hasMode(LoaderOptions.Mode.CONTEXT_MARK))), resolver);

         constructor.setComposer(composer);

         Iterator<Node> result = new Iterator<Node>() {

             public boolean hasNext() {

@@ -457,7 +483,8 @@
      * @return parsed events

      */

     public Iterable<Event> parse(Reader yaml) {

-        final Parser parser = new ParserImpl(new StreamReader(yaml, attachBufferToMark));

+        final Parser parser = new ParserImpl(new StreamReader(yaml, loaderOptions

+                .hasMode(LoaderOptions.Mode.CONTEXT_MARK)));

         Iterator<Event> result = new Iterator<Event>() {

             public boolean hasNext() {

                 return parser.peekEvent() != null;

@@ -491,10 +518,6 @@
         representer.getPropertyUtils().setBeanAccess(beanAccess);

     }

 

-    public void setAttachBufferToMark(boolean attachBufferToMark) {

-        this.attachBufferToMark = attachBufferToMark;

-    }

-

     // deprecated

     /**

      * @deprecated use with Constructor instead of Loader

diff --git a/src/test/java/org/yaml/snakeyaml/LoaderOptionsTest.java b/src/test/java/org/yaml/snakeyaml/LoaderOptionsTest.java
new file mode 100644
index 0000000..b12e0cd
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/LoaderOptionsTest.java
@@ -0,0 +1,30 @@
+/**

+ * Copyright (c) 2008-2010, http://code.google.com/p/snakeyaml/

+ *

+ * Licensed 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.yaml.snakeyaml;

+

+import junit.framework.TestCase;

+

+public class LoaderOptionsTest extends TestCase {

+

+    public void testGetMode() {

+        LoaderOptions defaultOptions = new LoaderOptions();

+        assertTrue(defaultOptions.hasMode(LoaderOptions.Mode.DYNAMIC_IMPLICIT_TYPES));

+        assertFalse(defaultOptions.hasMode(LoaderOptions.Mode.CONTEXT_MARK));

+        assertFalse(defaultOptions.hasMode(LoaderOptions.Mode.USE_IMPLICIT_TYPES));

+        assertFalse(defaultOptions.hasMode(LoaderOptions.Mode.COMPACT_FORMAT));

+    }

+}

diff --git a/src/test/java/org/yaml/snakeyaml/LoaderTest.java b/src/test/java/org/yaml/snakeyaml/LoaderTest.java
index 651b842..daec735 100644
--- a/src/test/java/org/yaml/snakeyaml/LoaderTest.java
+++ b/src/test/java/org/yaml/snakeyaml/LoaderTest.java
@@ -53,7 +53,7 @@
     }

 

     public void testCompose2() {

-        Yaml loader = new Yaml();

+        Yaml loader = new Yaml(new LoaderOptions(LoaderOptions.Mode.CONTEXT_MARK));

         String yaml = "3";

         ScalarNode node = (ScalarNode) loader.compose(new StringReader(yaml));

         assertEquals(Tag.INT, node.getTag());

@@ -71,9 +71,7 @@
     }

 

     public void testCompose3() {

-        Yaml loader = new Yaml();

-        // switch off the context for snippet

-        loader.setAttachBufferToMark(false);

+        Yaml loader = new Yaml();// switch off the context for snippet

         String yaml = "3";

         ScalarNode node = (ScalarNode) loader.compose(new StringReader(yaml));

         Mark mark = node.getStartMark();

diff --git a/src/test/java/org/yaml/snakeyaml/ParallelTest.java b/src/test/java/org/yaml/snakeyaml/ParallelTest.java
index ebb640f..b6b71ae 100644
--- a/src/test/java/org/yaml/snakeyaml/ParallelTest.java
+++ b/src/test/java/org/yaml/snakeyaml/ParallelTest.java
@@ -57,7 +57,6 @@
         public void run() {

             System.out.println("Started: " + id);

             Yaml yaml = new Yaml(new Constructor(Invoice.class));

-            yaml.setAttachBufferToMark(false);

             long time1 = System.nanoTime();

             int cycles = 200;

             for (int i = 0; i < cycles; i++) {

diff --git a/src/test/java/org/yaml/snakeyaml/StressTest.java b/src/test/java/org/yaml/snakeyaml/StressTest.java
index 3ff3e60..ecdcc7d 100644
--- a/src/test/java/org/yaml/snakeyaml/StressTest.java
+++ b/src/test/java/org/yaml/snakeyaml/StressTest.java
@@ -37,7 +37,6 @@
         System.out.println("Init was " + duration + " ms.");

 

         Yaml yaml = new Yaml(new Constructor(Invoice.class));

-        yaml.setAttachBufferToMark(false);

         time1 = System.nanoTime();

         yaml.load(doc);

         time2 = System.nanoTime();

@@ -45,7 +44,6 @@
         System.out.println("\nSingle load was " + duration + " ms.");

 

         yaml = new Yaml(new Constructor(Invoice.class));

-        yaml.setAttachBufferToMark(false);

         int[] range = new int[] { 1000, 2000 };

         System.out.println("\nOne instance.");

         for (int number : range) {

@@ -68,7 +66,6 @@
             time1 = System.nanoTime();

             for (int i = 0; i < number; i++) {

                 yaml = new Yaml(new Constructor(Invoice.class));

-                yaml.setAttachBufferToMark(false);

                 yaml.load(doc);

             }

             time2 = System.nanoTime();

diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue67/NonAsciiCharsInClassNameTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue67/NonAsciiCharsInClassNameTest.java
index 0fb4aa3..34291c7 100644
--- a/src/test/java/org/yaml/snakeyaml/issues/issue67/NonAsciiCharsInClassNameTest.java
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue67/NonAsciiCharsInClassNameTest.java
@@ -18,6 +18,7 @@
 

 import junit.framework.TestCase;

 

+import org.yaml.snakeyaml.LoaderOptions;

 import org.yaml.snakeyaml.Util;

 import org.yaml.snakeyaml.Yaml;

 import org.yaml.snakeyaml.nodes.Tag;

@@ -57,7 +58,7 @@
 

     public void testLoadInvalidPatternTooShort() {

         try {

-            Yaml yaml = new Yaml();

+            Yaml yaml = new Yaml(new LoaderOptions(LoaderOptions.Mode.CONTEXT_MARK));

             yaml.load(PREFIX + "Acad%9%A9mico {id: 3, name: Foo bar}");

             fail("Illegal hex characters in escape (%) pattern must not be accepted.");

         } catch (ScannerException e) {

@@ -70,7 +71,7 @@
 

     public void testLoadInvalidUtf8() {

         try {

-            Yaml yaml = new Yaml();

+            Yaml yaml = new Yaml(new LoaderOptions(LoaderOptions.Mode.CONTEXT_MARK));

             yaml.load(PREFIX + "Acad%C0mico {id: 3, name: Foo bar}");

             fail("Illegal UTF-8 must not be accepted.");

         } catch (ScannerException e) {