PARQUET-2467: Archive this repo (#504)

* Update the README

* Remove archived contents
diff --git a/.clang-format b/.clang-format
deleted file mode 100644
index 06453df..0000000
--- a/.clang-format
+++ /dev/null
@@ -1,20 +0,0 @@
-# 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.
----
-BasedOnStyle:  Google
-DerivePointerAlignment: false
-ColumnLimit: 90
diff --git a/.clang-tidy b/.clang-tidy
deleted file mode 100644
index bae34bc..0000000
--- a/.clang-tidy
+++ /dev/null
@@ -1,30 +0,0 @@
-# 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.
-
----
-Checks:          'clang-diagnostic-*,clang-analyzer-*,-clang-analyzer-alpha*,google-.*,modernize-.*,readablity-.*'
-HeaderFilterRegex: 'parquet/.*'
-AnalyzeTemporaryDtors: true
-CheckOptions:
-  - key:             google-readability-braces-around-statements.ShortStatementLines
-    value:           '1'
-  - key:             google-readability-function-size.StatementThreshold
-    value:           '800'
-  - key:             google-readability-namespace-comments.ShortNamespaceLines
-    value:           '10'
-  - key:             google-readability-namespace-comments.SpacesBeforeComments
-    value:           '2'
diff --git a/.clang-tidy-ignore b/.clang-tidy-ignore
deleted file mode 100644
index 8b13789..0000000
--- a/.clang-tidy-ignore
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/.parquetcppversion b/.parquetcppversion
deleted file mode 100644
index f825f7c..0000000
--- a/.parquetcppversion
+++ /dev/null
@@ -1 +0,0 @@
-1.5.1-SNAPSHOT
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index e1faf68..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,108 +0,0 @@
-# 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.
-
-sudo: required
-dist: trusty
-
-language: cpp
-
-cache:
-  ccache: true
-
-addons:
-  apt:
-    sources:
-    - ubuntu-toolchain-r-test
-    packages:
-    - gcc-4.9
-    - g++-4.9
-    - valgrind
-    - libboost-dev
-    - libboost-filesystem-dev
-    - libboost-regex-dev
-    - libboost-system-dev
-    - libboost-program-options-dev
-    - libboost-test-dev
-    - libssl-dev
-    - libtool
-    - bison
-    - flex
-    - pkg-config
-
-matrix:
-  fast_finish: true
-  include:
-  - compiler: gcc
-    os: linux
-    before_script:
-    - export PARQUET_CXXFLAGS="-DARROW_NO_DEPRECATED_API"
-    - export PARQUET_TRAVIS_VALGRIND=1
-    - source $TRAVIS_BUILD_DIR/ci/before_script_travis.sh
-  - compiler: clang
-    os: linux
-    before_script:
-    - export PARQUET_CXXFLAGS="-DARROW_NO_DEPRECATED_API"
-    - source $TRAVIS_BUILD_DIR/ci/before_script_travis.sh
-  - compiler: clang
-    os: osx
-    osx_image: xcode6.4
-    addons:
-    before_script:
-    - export PARQUET_CXXFLAGS="-DARROW_NO_DEPRECATED_API"
-    - source $TRAVIS_BUILD_DIR/ci/before_script_travis.sh
-    before_install:
-    - mkdir $TRAVIS_BUILD_DIR/parquet-build
-    - pushd $TRAVIS_BUILD_DIR/parquet-build
-  - compiler: gcc
-    os: linux
-    env: PARQUET_BUILD_GROUP=toolchain
-    before_script:
-    script:
-    - export PARQUET_CXXFLAGS="-DARROW_NO_DEPRECATED_API"
-    - $TRAVIS_BUILD_DIR/ci/travis_script_static.sh
-  - compiler: gcc
-    os: linux
-    env: PARQUET_BUILD_GROUP=toolchain
-    before_script:
-    script:
-    - $TRAVIS_BUILD_DIR/ci/travis_script_toolchain.sh
-
-# PARQUET-626: revisit llvm toolchain when/if llvm.org apt repo resurfaces
-
-# before_install:
-# - wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key|sudo apt-key add -
-# - sudo apt-get install -y software-properties-common
-# - sudo add-apt-repository -y ppa:george-edison55/cmake-3.x
-# - sudo apt-add-repository -y "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7
-#   main"
-# - sudo apt-add-repository -y "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.8
-#   main"
-# - sudo apt-get update
-# - sudo apt-get install -y clang-tidy-3.7 clang-format-3.7 cmake
-# - mkdir $TRAVIS_BUILD_DIR/parquet-build
-# - pushd $TRAVIS_BUILD_DIR/parquet-build
-
-before_install:
-- mkdir $TRAVIS_BUILD_DIR/parquet-build
-- pushd $TRAVIS_BUILD_DIR/parquet-build
-
-script:
-- $TRAVIS_BUILD_DIR/ci/travis_script_cpp.sh
-
-env:
-  global:
-  - secure: "sGGfe2N9i2dItR0FryQYZDdzdi9gl6QFXxGWxxXWfPz+mideJWaMLSA17dsWkbrag5GlAcs+8BRGWWagAXicPlOqD1tKKJqZxA4PEPDECny26Sh/pebZvmvnAV5136sXkKXMQkcTfoo3v22zYdVthVa+8EQTXKxGzhbL61AosSk="
diff --git a/CHANGELOG b/CHANGELOG
deleted file mode 100644
index 4673741..0000000
--- a/CHANGELOG
+++ /dev/null
@@ -1,503 +0,0 @@
-Parquet C++ 1.5.0
---------------------------------------------------------------------------------
-## Bug
-    * [PARQUET-979] - [C++] Limit size of min, max or disable stats for long binary types
-    * [PARQUET-1071] - [C++] parquet::arrow::FileWriter::Close is not idempotent
-    * [PARQUET-1349] - [C++] PARQUET_RPATH_ORIGIN is not picked by the build
-    * [PARQUET-1334] - [C++] memory_map parameter seems missleading in parquet file opener
-    * [PARQUET-1333] - [C++] Reading of files with dictionary size 0 fails on Windows with bad_alloc
-    * [PARQUET-1283] - [C++] FormatStatValue appends trailing space to string and int96
-    * [PARQUET-1270] - [C++] Executable tools do not get installed
-    * [PARQUET-1272] - [C++] ScanFileContents reports wrong row count for nested columns
-    * [PARQUET-1268] - [C++] Conversion of Arrow null list columns fails
-    * [PARQUET-1255] - [C++] Exceptions thrown in some tests
-    * [PARQUET-1358] - [C++] index_page_offset should be unset as it is not supported.
-    * [PARQUET-1357] - [C++] FormatStatValue truncates binary statistics on zero character
-    * [PARQUET-1319] - [C++] Pass BISON_EXECUTABLE to Thrift EP for MacOS
-    * [PARQUET-1313] - [C++] Compilation failure with VS2017
-    * [PARQUET-1315] - [C++] ColumnChunkMetaData.has_dictionary_page() should return bool, not int64_t
-    * [PARQUET-1307] - [C++] memory-test fails with latest Arrow
-    * [PARQUET-1274] - [Python] SegFault in pyarrow.parquet.write_table with specific options
-    * [PARQUET-1209] - locally defined symbol ... imported in function ..
-    * [PARQUET-1245] - [C++] Segfault when writing Arrow table with duplicate columns
-    * [PARQUET-1273] - [Python] Error writing to partitioned Parquet dataset
-    * [PARQUET-1384] - [C++] Clang compiler warnings in bloom_filter-test.cc
-
-## Improvement
-    * [PARQUET-1348] - [C++] Allow Arrow FileWriter To Write FileMetaData
-    * [PARQUET-1346] - [C++] Protect against null values data in empty Arrow array
-    * [PARQUET-1340] - [C++] Fix Travis Ci valgrind errors related to std::random_device
-    * [PARQUET-1323] - [C++] Fix compiler warnings with clang-6.0
-    * [PARQUET-1279] - Use ASSERT_NO_FATAIL_FAILURE in C++ unit tests
-    * [PARQUET-1262] - [C++] Use the same BOOST_ROOT and Boost_NAMESPACE for Thrift 
-    * [PARQUET-1267] - replace "unsafe" std::equal by std::memcmp
-    * [PARQUET-1360] - [C++] Minor API + style changes follow up to PARQUET-1348
-    * [PARQUET-1166] - [API Proposal] Add GetRecordBatchReader in parquet/arrow/reader.h
-    * [PARQUET-1378] - [c++] Allow RowGroups with zero rows to be written
-    * [PARQUET-1256] - [C++] Add --print-key-value-metadata option to parquet_reader tool
-    * [PARQUET-1276] - [C++] Reduce the amount of memory used for writing null decimal values
-
-## New Feature
-    * [PARQUET-1392] - [C++] Supply row group indices to parquet::arrow::FileReader::ReadTable
-
-## Sub-task
-    * [PARQUET-1227] - Thrift crypto metadata structures
-    * [PARQUET-1332] - [C++] Add bloom filter utility class
-
-## Task
-    * [PARQUET-1350] - [C++] Use abstract ResizableBuffer instead of concrete PoolBuffer
-    * [PARQUET-1366] - [C++] Streamline use of Arrow bit-util.h
-    * [PARQUET-1308] - [C++] parquet::arrow should use thread pool, not ParallelFor
-    * [PARQUET-1382] - [C++] Prepare for arrow::test namespace removal
-    * [PARQUET-1372] - [C++] Add an API to allow writing RowGroups based on their size rather than num_rows
-
-
-Parquet C++ 1.4.0
---------------------------------------------------------------------------------
-## Bug
-    * [PARQUET-1193] - [CPP] Implement ColumnOrder to support min_value and max_value
-    * [PARQUET-1180] - C++: Fix behaviour of num_children element of primitive nodes
-    * [PARQUET-1146] - C++: Add macOS-compatible sha512sum call to release verify script
-    * [PARQUET-1167] - [C++] FieldToNode function should return a status when throwing an exception
-    * [PARQUET-1175] - [C++] Fix usage of deprecated Arrow API
-    * [PARQUET-1113] - [C++] Incorporate fix from ARROW-1601 on bitmap read path
-    * [PARQUET-1111] - dev/release/verify-release-candidate has stale help
-    * [PARQUET-1109] - C++: Update release verification script to SHA512
-    * [PARQUET-1179] - [C++] Support Apache Thrift 0.11
-    * [PARQUET-1226] - [C++] Fix new build warnings with clang 5.0
-    * [PARQUET-1233] - [CPP ]Enable option to switch between stl classes and boost classes for thrift header
-    * [PARQUET-1205] - Fix msvc static build
-    * [PARQUET-1210] - [C++] Boost 1.66 compilation fails on Windows on linkage stage
-
-## Improvement
-    * [PARQUET-1092] - [C++] Write Arrow tables with chunked columns
-    * [PARQUET-1086] - [C++] Remove usage of arrow/util/compiler-util.h after 1.3.0 release
-    * [PARQUET-1097] - [C++] Account for Arrow API deprecation in ARROW-1511
-    * [PARQUET-1150] - C++: Hide statically linked boost symbols
-    * [PARQUET-1151] - [C++] Add build options / configuration to use static runtime libraries with MSVC
-    * [PARQUET-1147] - [C++] Account for API deprecation / change in ARROW-1671
-    * [PARQUET-1162] - C++: Update dev/README after migration to Gitbox
-    * [PARQUET-1165] - [C++] Pin clang-format version to 4.0
-    * [PARQUET-1164] - [C++] Follow API changes in ARROW-1808
-    * [PARQUET-1177] - [C++] Add more extensive compiler warnings when using Clang
-    * [PARQUET-1110] - [C++] Release verification script for Windows
-    * [PARQUET-859] - [C++] Flatten parquet/file directory
-    * [PARQUET-1220] - [C++] Don't build Thrift examples and tutorials in the ExternalProject
-    * [PARQUET-1219] - [C++] Update release-candidate script links to gitbox
-    * [PARQUET-1196] - [C++] Provide a parquet_arrow example project incl. CMake setup
-    * [PARQUET-1200] - [C++] Support reading a single Arrow column from a Parquet file
-
-## New Feature
-    * [PARQUET-1095] - [C++] Read and write Arrow decimal values
-    * [PARQUET-970] - Add Add Lz4 and Zstd compression codecs
-
-## Task
-    * [PARQUET-1221] - [C++] Extend release README
-    * [PARQUET-1225] - NaN values may lead to incorrect filtering under certain circumstances
-
-
-Parquet C++ 1.3.1
---------------------------------------------------------------------------------
-## Bug
-    * [PARQUET-1105] - [CPP] Remove libboost_system dependency 
-    * [PARQUET-1138] - [C++] Fix compilation with Arrow 0.7.1
-    * [PARQUET-1123] - [C++] Update parquet-cpp to use Arrow's AssertArraysEqual
-    * [PARQUET-1121] - C++: DictionaryArrays of NullType cannot be written
-    * [PARQUET-1139] - Add license to cmake_modules/parquet-cppConfig.cmake.in
-
-## Improvement
-    * [PARQUET-1140] - [C++] Fail on RAT errors in CI
-    * [PARQUET-1070] - Add CPack support to the build
-
-
-Parquet C++ 1.3.0
---------------------------------------------------------------------------------
-## Bug
-    * [PARQUET-1098] - [C++] Install new header in parquet/util
-    * [PARQUET-1085] - [C++] Backwards compatibility from macro cleanup in transitive dependencies in ARROW-1452
-    * [PARQUET-1074] - [C++] Switch to long key ids in KEYs file
-    * [PARQUET-1075] - C++: Coverage upload is broken
-    * [PARQUET-1088] - [CPP] remove parquet_version.h from version control since it gets auto generated 
-    * [PARQUET-1002] - [C++] Compute statistics based on Logical Types
-    * [PARQUET-1100] - [C++] Reading repeated types should decode number of records rather than number of values
-    * [PARQUET-1090] - [C++] Fix int32 overflow in Arrow table writer, add max row group size property
-    * [PARQUET-1108] - [C++] Fix Int96 comparators
-
-## Improvement
-    * [PARQUET-1104] - [C++] Upgrade to Apache Arrow 0.7.0 RC0
-    * [PARQUET-1072] - [C++] Add ARROW_NO_DEPRECATED_API to CI to check for deprecated API use
-    * [PARQUET-1096] - C++: Update sha{1, 256, 512} checksums per latest ASF release policy
-    * [PARQUET-1079] - [C++] Account for Arrow API change in ARROW-1335
-    * [PARQUET-1087] - [C++] Add wrapper for ScanFileContents in parquet::arrow that catches exceptions
-    * [PARQUET-1093] - C++: Improve Arrow level generation error message
-    * [PARQUET-1094] - C++: Add benchmark for boolean Arrow column I/O
-    * [PARQUET-1083] - [C++] Refactor core logic in parquet-scan.cc so that it can be used as a library function for benchmarking
-    * [PARQUET-1037] - Allow final RowGroup to be unfilled
-
-## New Feature
-    * [PARQUET-1078] - [C++] Add Arrow writer option to coerce timestamps to milliseconds or microseconds
-    * [PARQUET-929] - [C++] Handle arrow::DictionaryArray when writing Arrow data
-
-
-Parquet C++ 1.2.0
---------------------------------------------------------------------------------
-## Bug
-    * [PARQUET-1029] - [C++] TypedColumnReader/TypeColumnWriter symbols are no longer being exported
-    * [PARQUET-997] - Fix override compiler warnings
-    * [PARQUET-1033] - Mismatched Read and Write
-    * [PARQUET-1007] - [C++ ] Update parquet.thrift from https://github.com/apache/parquet-format
-    * [PARQUET-1039] - PARQUET-911 Breaks Arrow
-    * [PARQUET-1038] - Key value metadata should be nullptr if not set
-    * [PARQUET-1018] - [C++] parquet.dll has runtime dependencies on one or more libraries in the build toolchain
-    * [PARQUET-1003] - [C++] Modify DEFAULT_CREATED_BY value for every new release version
-    * [PARQUET-1004] - CPP Building fails on windows
-    * [PARQUET-1040] - Missing writer method implementations
-    * [PARQUET-1054] - [C++] Account for Arrow API changes in ARROW-1199
-    * [PARQUET-1042] - C++: Compilation breaks on GCC 4.8
-    * [PARQUET-1048] - [C++] Static linking of libarrow is no longer supported
-    * [PARQUET-1013] - Fix ZLIB_INCLUDE_DIR
-    * [PARQUET-998] - C++: Release script is not usable
-    * [PARQUET-1023] - [C++] Brotli libraries are not being statically linked on Windows
-    * [PARQUET-1000] - [C++] Do not build thirdparty Arrow with /WX on MSVC
-    * [PARQUET-1052] - [C++] add_compiler_export_flags() throws warning with CMake >= 3.3
-    * [PARQUET-1069] - C++: ./dev/release/verify-release-candidate is broken due to missing Arrow dependencies
-
-## Improvement
-    * [PARQUET-996] - Improve MSVC build - ThirdpartyToolchain - Arrow
-    * [PARQUET-911] - C++: Support nested structs in parquet_arrow
-    * [PARQUET-986] - Improve MSVC build - ThirdpartyToolchain - Thrift
-    * [PARQUET-864] - [C++] Consolidate non-Parquet-specific bit utility code into Apache Arrow
-    * [PARQUET-1043] - [C++] Raise minimum supported CMake version to 3.2
-    * [PARQUET-1016] - Upgrade thirdparty Arrow to 0.4.0
-    * [PARQUET-858] - [C++] Flatten parquet/column directory, consolidate related code
-    * [PARQUET-978] - [C++] Minimizing footer reads for small(ish) metadata
-    * [PARQUET-991] - [C++] Fix compiler warnings on MSVC and build with /WX in Appveyor
-    * [PARQUET-863] - [C++] Move SIMD, CPU info, hashing, and other generic utilities into Apache Arrow
-    * [PARQUET-1053] - Fix unused result warnings due to unchecked Statuses
-    * [PARQUET-1067] - C++: Update arrow hash to 0.5.0
-    * [PARQUET-1041] - C++: Support Arrow's NullArray
-    * [PARQUET-1008] - Update TypedColumnReader::ReadBatch method to accept batch_size as int64_t
-    * [PARQUET-1044] - [C++] Use compression libraries from Apache Arrow
-    * [PARQUET-999] - Improve MSVC build - Enable PARQUET_BUILD_BENCHMARKS
-    * [PARQUET-967] - [C++] Combine libparquet/libparquet_arrow libraries
-    * [PARQUET-1045] - [C++] Refactor to account for computational utility code migration in ARROW-1154
-
-## New Feature
-    * [PARQUET-1035] - Write Int96 from Arrow Timestamp(ns)
-
-## Task
-    * [PARQUET-994] - C++: release-candidate script should not push to master
-    * [PARQUET-902] - [C++] Move compressor interfaces into Apache Arrow
-
-## Test
-    * [PARQUET-706] - [C++] Create test case that uses libparquet as a 3rd party library
-
-
-Parquet C++ 1.1.0
---------------------------------------------------------------------------------
-## Bug
-    * [PARQUET-898] - [C++] Change Travis CI OS X image to Xcode 6.4 and fix our thirdparty build
-    * [PARQUET-976] - [C++] Pass unit test suite with MSVC, build in Appveyor
-    * [PARQUET-963] - [C++] Disallow reading struct types in Arrow reader for now
-    * [PARQUET-959] - [C++] Arrow thirdparty build fails on multiarch systems
-    * [PARQUET-962] - [C++] GTEST_MAIN_STATIC_LIB is not defined in FindGTest.cmake
-    * [PARQUET-958] - [C++] Print Parquet metadata in JSON format
-    * [PARQUET-956] - C++: BUILD_BYPRODUCTS not specified anymore for gtest
-    * [PARQUET-948] - [C++] Account for API changes in ARROW-782
-    * [PARQUET-947] - [C++] Refactor to account for ARROW-795 Arrow core library consolidation
-    * [PARQUET-965] - [C++] FIXED_LEN_BYTE_ARRAY types are unhandled in the Arrow reader
-    * [PARQUET-949] - [C++] Arrow version pinning seems to not be working properly
-    * [PARQUET-955] - [C++] pkg_check_modules will override $ARROW_HOME if it is set in the environment
-    * [PARQUET-945] - [C++] Thrift static libraries are not used with recent patch
-    * [PARQUET-943] - [C++] Overflow build error on x86
-    * [PARQUET-938] - [C++] There is a typo in cmake_modules/FindSnappy.cmake comment
-    * [PARQUET-936] - [C++] parquet::arrow::WriteTable can enter infinite loop if chunk_size is 0
-    * [PARQUET-981] - Repair usage of *_HOME 3rd party dependencies environment variables during Windows build 
-    * [PARQUET-992] - [C++] parquet/compression.h leaks zlib.h
-    * [PARQUET-987] - [C++] Fix regressions caused by PARQUET-981
-    * [PARQUET-933] - [C++] Account for Arrow Table API changes coming in ARROW-728
-    * [PARQUET-915] - Support Arrow Time Types in Schema
-    * [PARQUET-914] - [C++] Throw more informative exception when user writes too many values to a column in a row group
-    * [PARQUET-923] - [C++] Account for Time metadata changes in ARROW-686
-    * [PARQUET-918] - FromParquetSchema API crashes on nested schemas
-    * [PARQUET-925] - [C++] FindArrow.cmake sets the wrong library path after ARROW-648
-    * [PARQUET-932] - [c++] Add option to build parquet library with minimal dependency
-    * [PARQUET-919] - [C++] Account for API changes in ARROW-683
-    * [PARQUET-995] - [C++] Int96 reader in parquet_arrow uses size of Int96Type instead of Int96
-
-## Improvement
-    * [PARQUET-508] - Add ParquetFilePrinter
-    * [PARQUET-595] - Add API for key-value metadata
-    * [PARQUET-897] - [C++] Only use designated public headers from libarrow
-    * [PARQUET-679] - [C++] Build and unit tests support for MSVC on Windows
-    * [PARQUET-977] - Improve MSVC build
-    * [PARQUET-957] - [C++] Add optional $PARQUET_BUILD_TOOLCHAIN environment variable option for configuring build environment
-    * [PARQUET-961] - [C++] Strip debug symbols from libparquet libraries in release builds by default
-    * [PARQUET-954] - C++: Use Brolti 0.6 release
-    * [PARQUET-953] - [C++] Change arrow::FileWriter API to be initialized from a Schema, and provide for writing multiple tables
-    * [PARQUET-941] - [C++] Stop needless Boost static library detection for CentOS 7 support
-    * [PARQUET-942] - [C++] Fix wrong variabe use in FindSnappy
-    * [PARQUET-939] - [C++] Support Thrift_HOME CMake variable like FindSnappy does as Snappy_HOME
-    * [PARQUET-940] - [C++] Fix Arrow library path detection
-    * [PARQUET-937] - [C++] Support CMake < 3.4 again for Arrow detection
-    * [PARQUET-935] - [C++] Set shared library version for .deb packages
-    * [PARQUET-934] - [C++] Support multiarch on Debian
-    * [PARQUET-984] - C++: Add abi and so version to pkg-config
-    * [PARQUET-983] - C++: Update Thirdparty hash to Arrow 0.3.0
-    * [PARQUET-989] - [C++] Link dynamically to libarrow in toolchain build, set LD_LIBRARY_PATH
-    * [PARQUET-988] - [C++] Add Linux toolchain-based build to Travis CI
-    * [PARQUET-928] - [C++] Support pkg-config
-    * [PARQUET-927] - [C++] Specify shared library version of Apache Arrow
-    * [PARQUET-931] - [C++] Add option to pin thirdparty Arrow version used in ExternalProject
-    * [PARQUET-926] - [C++] Use pkg-config to find Apache Arrow
-    * [PARQUET-917] - C++: Build parquet_arrow by default
-    * [PARQUET-910] - C++: Support TIME logical type in parquet_arrow
-    * [PARQUET-909] - [CPP]: Reduce buffer allocations (mallocs) on critical path
-
-## New Feature
-    * [PARQUET-853] - [C++] Add option to link with shared boost libraries when building Arrow in the thirdparty toolchain
-    * [PARQUET-946] - [C++] Refactoring in parquet::arrow::FileReader to be able to read a single row group
-    * [PARQUET-930] - [C++] Account for all Arrow date/time types 
-
-
-Parquet C++ 1.0.0
---------------------------------------------------------------------------------
-## Bug
-    * [PARQUET-455] - Fix compiler warnings on OS X / Clang
-    * [PARQUET-558] - Support ZSH in build scripts
-    * [PARQUET-720] - Parquet-cpp fails to link when included in multiple TUs
-    * [PARQUET-718] - Reading boolean pages written by parquet-cpp fails
-    * [PARQUET-640] - [C++] Force the use of gcc 4.9 in conda builds
-    * [PARQUET-643] - Add const modifier to schema pointer reference in ParquetFileWriter
-    * [PARQUET-672] - [C++] Build testing conda artifacts in debug mode
-    * [PARQUET-661] - [C++] Do not assume that perl is found in /usr/bin
-    * [PARQUET-659] - [C++] Instantiated template visibility is broken on clang / OS X
-    * [PARQUET-657] - [C++] Don't define DISALLOW_COPY_AND_ASSIGN if already defined
-    * [PARQUET-656] - [C++] Revert PARQUET-653
-    * [PARQUET-676] - MAX_VALUES_PER_LITERAL_RUN causes RLE encoding failure
-    * [PARQUET-614] - C++: Remove unneeded LZ4-related code
-    * [PARQUET-604] - Install writer.h headers
-    * [PARQUET-621] - C++: Uninitialised DecimalMetadata is read
-    * [PARQUET-620] - C++: Duplicate calls to ParquetFileWriter::Close cause duplicate metdata writes
-    * [PARQUET-599] - ColumnWriter::RleEncodeLevels' size estimation might be wrong
-    * [PARQUET-617] - C++: Enable conda build to work on systems with non-default C++ toolchains
-    * [PARQUET-627] - Ensure that thrift headers are generated before source compilation
-    * [PARQUET-745] - TypedRowGroupStatistics fails to PlainDecode min and max in ByteArrayType
-    * [PARQUET-738] - Update arrow version that also supports newer Xcode
-    * [PARQUET-747] - [C++] TypedRowGroupStatistics are not being exported in libparquet.so
-    * [PARQUET-711] - Use metadata builders in parquet writer
-    * [PARQUET-732] - Building a subset of dependencies does not work
-    * [PARQUET-760] - On switching from dictionary to the fallback encoding, an incorrect encoding is set
-    * [PARQUET-691] - [C++] Write ColumnChunk metadata after each column chunk in the file
-    * [PARQUET-797] - [C++] Update for API changes in ARROW-418
-    * [PARQUET-837] - [C++] SerializedFile::ParseMetaData uses Seek, followed by Read, and could have race conditions
-    * [PARQUET-827] - [C++] Incorporate addition of arrow::MemoryPool::Reallocate
-    * [PARQUET-502] - Scanner segfaults when its batch size is smaller than the number of rows
-    * [PARQUET-469] - Roll back Thrift bindings to 0.9.0
-    * [PARQUET-889] - Fix compilation when PARQUET_USE_SSE is on
-    * [PARQUET-888] - C++ Memory leak in RowGroupSerializer
-    * [PARQUET-819] - C++: Trying to install non-existing parquet/arrow/utils.h
-    * [PARQUET-736] - XCode 8.0 breaks builds
-    * [PARQUET-505] - Column reader: automatically handle large data pages
-    * [PARQUET-615] - C++: Building static or shared libparquet should not be mutually exclusive
-    * [PARQUET-658] - ColumnReader has no virtual destructor
-    * [PARQUET-799] - concurrent usage of the file reader API
-    * [PARQUET-513] - Valgrind errors are not failing the Travis CI build
-    * [PARQUET-841] - [C++] Writing wrong format version when using ParquetVersion::PARQUET_1_0
-    * [PARQUET-742] - Add missing license headers
-    * [PARQUET-741] - compression_buffer_ is reused although it shouldn't
-    * [PARQUET-700] - C++: Disable dictionary encoding for boolean columns
-    * [PARQUET-662] - [C++] ParquetException must be explicitly exported in dynamic libraries
-    * [PARQUET-704] - [C++] scan-all.h is not being installed
-    * [PARQUET-865] - C++: Pass all CXXFLAGS to Thrift ExternalProject
-    * [PARQUET-875] - [C++] Fix coveralls build given changes to thirdparty build procedure
-    * [PARQUET-709] - [C++] Fix conda dev binary builds
-    * [PARQUET-638] - [C++] Revert static linking of libstdc++ in conda builds until symbol visibility addressed
-    * [PARQUET-606] - Travis coverage is broken
-    * [PARQUET-880] - [CPP] Prevent destructors from throwing
-    * [PARQUET-886] - [C++] Revise build documentation and requirements in README.md
-    * [PARQUET-900] - C++: Fix NOTICE / LICENSE issues
-    * [PARQUET-885] - [C++] Do not search for Thrift in default system paths
-    * [PARQUET-879] - C++: ExternalProject compilation for Thrift fails on older CMake versions
-    * [PARQUET-635] - [C++] Statically link libstdc++ on Linux in conda recipe
-    * [PARQUET-710] - Remove unneeded private member variables from RowGroupReader ABI
-    * [PARQUET-766] - C++: Expose ParquetFileReader through Arrow reader as const
-    * [PARQUET-876] - C++: Correct snapshot version
-    * [PARQUET-821] - [C++] zlib download link is broken
-    * [PARQUET-818] - [C++] Refactor library to share IO, Buffer, and memory management abstractions with Apache Arrow
-    * [PARQUET-537] - LocalFileSource leaks resources
-    * [PARQUET-764] - [CPP] Parquet Writer does not write Boolean values correctly
-    * [PARQUET-812] - [C++] Failure reading BYTE_ARRAY data from file in parquet-compatibility project
-    * [PARQUET-759] - Cannot store columns consisting of empty strings
-    * [PARQUET-846] - [CPP] CpuInfo::Init() is not thread safe
-    * [PARQUET-694] - C++: Revert default data page size back to 1M
-    * [PARQUET-842] - [C++] Impala rejects DOUBLE columns if decimal metadata is set
-    * [PARQUET-708] - [C++] RleEncoder does not account for "worst case scenario" in MaxBufferSize for bit_width > 1
-    * [PARQUET-639] - Do not export DCHECK in public headers
-    * [PARQUET-828] - [C++] "version" field set improperly in file metadata
-    * [PARQUET-891] - [C++] Do not search for Snappy in default system paths
-    * [PARQUET-626] - Fix builds due to unavailable llvm.org apt mirror
-    * [PARQUET-629] - RowGroupSerializer should only close itself once
-    * [PARQUET-472] - Clean up InputStream ownership semantics in ColumnReader
-    * [PARQUET-739] - Rle-decoding uses static buffer that is shared accross threads
-    * [PARQUET-561] - ParquetFileReader::Contents PIMPL missing a virtual destructor
-    * [PARQUET-892] - [C++] Clean up link library targets in CMake files
-    * [PARQUET-454] - Address inconsistencies in boolean decoding
-    * [PARQUET-816] - [C++] Failure decoding sample dict-encoded file from parquet-compatibility project
-    * [PARQUET-565] - Use PATH instead of DIRECTORY in get_filename_component to support CMake<2.8.12
-    * [PARQUET-446] - Hide thrift dependency in parquet-cpp
-    * [PARQUET-843] - [C++] Impala unable to read files created by parquet-cpp
-    * [PARQUET-555] - Dictionary page metadata handling inconsistencies
-    * [PARQUET-908] - Fix for PARQUET-890 introduces undefined symbol in libparquet_arrow.so
-    * [PARQUET-793] - [CPP] Do not return incorrect statistics
-    * [PARQUET-887] - C++: Fix issues in release scripts arise in RC1
-
-## Improvement
-    * [PARQUET-277] - Remove boost dependency
-    * [PARQUET-500] - Enable coveralls.io for apache/parquet-cpp
-    * [PARQUET-497] - Decouple Parquet physical file structure from FileReader class
-    * [PARQUET-597] - Add data rates to benchmark output
-    * [PARQUET-522] - #include cleanup with include-what-you-use 
-    * [PARQUET-515] - Add "Reset" to LevelEncoder and LevelDecoder
-    * [PARQUET-514] - Automate coveralls.io updates in Travis CI
-    * [PARQUET-551] - Handle compiler warnings due to disabled DCHECKs in release builds
-    * [PARQUET-559] - Enable InputStream as a source to the ParquetFileReader
-    * [PARQUET-562] - Simplified ZSH support in build scripts
-    * [PARQUET-538] - Improve ColumnReader Tests
-    * [PARQUET-541] - Portable build scripts
-    * [PARQUET-724] - Test more advanced properties setting
-    * [PARQUET-641] - Instantiate stringstream only if needed in SerializedPageReader::NextPage
-    * [PARQUET-636] - Expose selection for different encodings
-    * [PARQUET-603] - Implement missing information in schema descriptor
-    * [PARQUET-610] - Print ColumnMetaData for each RowGroup
-    * [PARQUET-600] - Add benchmarks for RLE-Level encoding
-    * [PARQUET-592] - Support compressed writes
-    * [PARQUET-593] - Add API for writing Page statistics
-    * [PARQUET-589] - Implement Chunked InMemoryInputStream for better memory usage
-    * [PARQUET-587] - Implement BufferReader::Read(int64_t,uint8_t*)
-    * [PARQUET-616] - C++: WriteBatch should accept const arrays
-    * [PARQUET-630] - C++: Support link flags for older CMake versions
-    * [PARQUET-634] - Consistent private linking of dependencies
-    * [PARQUET-633] - Add version to WriterProperties
-    * [PARQUET-625] - Improve RLE read performance
-    * [PARQUET-737] - Use absolute namespace in macros
-    * [PARQUET-762] - C++: Use optimistic allocation instead of Arrow Builders
-    * [PARQUET-773] - C++: Check licenses with RAT in CI
-    * [PARQUET-687] - C++: Switch to PLAIN encoding if dictionary grows too large
-    * [PARQUET-784] - C++: Reference Spark, Kudu and FrameOfReference in LICENSE
-    * [PARQUET-809] - [C++] Add API to determine if two files' schemas are compatible 
-    * [PARQUET-778] - Standardize the schema output to match the parquet-mr format
-    * [PARQUET-463] - Add DCHECK* macros for assertions in debug builds
-    * [PARQUET-471] - Use the same environment setup script for Travis CI as local sandbox development
-    * [PARQUET-449] - Update to latest parquet.thrift
-    * [PARQUET-496] - Fix cpplint configuration to be more restrictive
-    * [PARQUET-468] - Add a cmake option to generate the Parquet thrift headers with the thriftc in the environment
-    * [PARQUET-482] - Organize src code file structure to have a very clear folder with public headers.
-    * [PARQUET-591] - Page size estimation during writes
-    * [PARQUET-518] - Review usages of size_t and unsigned integers generally per Google style guide
-    * [PARQUET-533] - Simplify RandomAccessSource API to combine Seek/Read 
-    * [PARQUET-767] - Add release scripts for parquet-cpp
-    * [PARQUET-699] - Update parquet.thrift from https://github.com/apache/parquet-format
-    * [PARQUET-653] - [C++] Re-enable -static-libstdc++ in dev artifact builds
-    * [PARQUET-763] - C++: Expose ParquetFileReader through Arrow reader
-    * [PARQUET-857] - [C++] Flatten parquet/encodings directory
-    * [PARQUET-862] - Provide defaut cache size values if CPU info probing is not available
-    * [PARQUET-689] - C++: Compress DataPages eagerly
-    * [PARQUET-874] - [C++] Use default memory allocator from Arrow
-    * [PARQUET-267] - Detach thirdparty code from build configuration.
-    * [PARQUET-418] - Add a utility to print contents of a Parquet file to stdout
-    * [PARQUET-519] - Disable compiler warning supressions and fix all DEBUG build warnings
-    * [PARQUET-447] - Add Debug and Release build types and associated compiler flags
-    * [PARQUET-868] - C++: Build snappy with optimizations
-    * [PARQUET-894] - Fix compilation warning
-    * [PARQUET-883] - C++: Support non-standard gcc version strings
-    * [PARQUET-607] - Public Writer header
-    * [PARQUET-731] - [CPP] Add API to return metadata size and Skip reading values
-    * [PARQUET-628] - Link thrift privately
-    * [PARQUET-877] - C++: Update Arrow Hash, update Version in metadata.
-    * [PARQUET-547] - Refactor most templates to use DataType structs rather than the Type::type enum
-    * [PARQUET-882] - [CPP] Improve Application Version parsing
-    * [PARQUET-448] - Add cmake option to skip building the unit tests
-    * [PARQUET-721] - Performance benchmarks for reading into Arrow structures
-    * [PARQUET-820] - C++: Decoders should directly emit arrays with spacing for null entries
-    * [PARQUET-813] - C++: Build dependencies using CMake External project
-    * [PARQUET-488] - Add SSE-related cmake options to manage compiler flags
-    * [PARQUET-564] - Add option to run unit tests with valgrind --tool=memcheck
-    * [PARQUET-572] - Rename parquet_cpp namespace to parquet
-    * [PARQUET-829] - C++: Make use of ARROW-469
-    * [PARQUET-501] - Add an OutputStream abstraction (capable of memory allocation) for Encoder public API
-    * [PARQUET-744] - Clarifications on build instructions
-    * [PARQUET-520] - Add version of LocalFileSource that uses memory-mapping for zero-copy reads
-    * [PARQUET-556] - Extend RowGroupStatistics to include "min" "max" statistics
-    * [PARQUET-671] - Improve performance of RLE/bit-packed decoding in parquet-cpp
-    * [PARQUET-681] - Add tool to scan a parquet file
-
-## New Feature
-    * [PARQUET-499] - Complete PlainEncoder implementation for all primitive types and test end to end
-    * [PARQUET-439] - Conform all copyright headers to ASF requirements
-    * [PARQUET-436] - Implement ParquetFileWriter class entry point for generating new Parquet files
-    * [PARQUET-435] - Provide vectorized ColumnReader interface
-    * [PARQUET-438] - Update RLE encoder/decoder modules from Impala upstream changes and adapt unit tests
-    * [PARQUET-512] - Add optional google/benchmark 3rd-party dependency for performance testing
-    * [PARQUET-566] - Add method to retrieve the full column path
-    * [PARQUET-613] - C++: Add conda packaging recipe
-    * [PARQUET-605] - Expose schema node in ColumnDescriptor
-    * [PARQUET-619] - C++: Add OutputStream for local files
-    * [PARQUET-583] - Implement Parquet to Thrift schema conversion
-    * [PARQUET-582] - Conversion functions for Parquet enums to Thrift enums
-    * [PARQUET-728] - [C++] Bring parquet::arrow up to date with API changes in arrow::io 
-    * [PARQUET-752] - [C++] Conform parquet_arrow to upstream API changes
-    * [PARQUET-788] - [C++] Reference Impala / Apache Impala (incubating) in LICENSE
-    * [PARQUET-808] - [C++] Add API to read file given externally-provided FileMetadata
-    * [PARQUET-807] - [C++] Add API to read file metadata only from a file handle
-    * [PARQUET-805] - C++: Read Int96 into Arrow Timestamp(ns)
-    * [PARQUET-836] - [C++] Add column selection to parquet::arrow::FileReader
-    * [PARQUET-835] - [C++] Add option to parquet::arrow to read columns in parallel using a thread pool
-    * [PARQUET-830] - [C++] Add additional configuration options to parquet::arrow::OpenFIle
-    * [PARQUET-769] - C++: Add support for Brotli Compression
-    * [PARQUET-489] - Add visibility macros to be used for public and internal APIs of libparquet
-    * [PARQUET-542] - Support memory allocation from external memory
-    * [PARQUET-844] - [C++] Consolidate encodings, schema, and compression subdirectories into fewer files
-    * [PARQUET-848] - [C++] Consolidate libparquet_thrift subcomponent
-    * [PARQUET-646] - [C++] Enable easier 3rd-party toolchain clang builds on Linux
-    * [PARQUET-598] - [C++] Test writing all primitive data types
-    * [PARQUET-442] - Convert flat SchemaElement vector to implied nested schema data structure
-    * [PARQUET-867] - [C++] Support writing sliced Arrow arrays
-    * [PARQUET-456] - Add zlib codec support
-    * [PARQUET-834] - C++: Support r/w of arrow::ListArray
-    * [PARQUET-485] - Decouple data page delimiting from column reader / scanner classes, create test fixtures
-    * [PARQUET-434] - Add a ParquetFileReader class to encapsulate some low-level details of interacting with Parquet files
-    * [PARQUET-666] - PLAIN_DICTIONARY write support
-    * [PARQUET-437] - Incorporate googletest thirdparty dependency and add cmake tools (ADD_PARQUET_TEST) to simplify adding new unit tests
-    * [PARQUET-866] - [C++] Account for API changes in ARROW-33
-    * [PARQUET-545] - Improve API to support Decimal type
-    * [PARQUET-579] - Add API for writing Column statistics
-    * [PARQUET-494] - Implement PLAIN_DICTIONARY encoding and decoding
-    * [PARQUET-618] - C++: Automatically upload conda build artifacts on commits to master
-    * [PARQUET-833] - C++: Provide API to write spaced arrays (e.g. Arrow)
-    * [PARQUET-903] - C++: Add option to set RPATH to ORIGIN
-    * [PARQUET-451] - Add a RowGroup reader interface class
-    * [PARQUET-785] - C++: List conversion for Arrow Schemas
-    * [PARQUET-712] - C++: Read into Arrow memory
-    * [PARQUET-890] - C++: Support I/O of DATE columns in parquet_arrow
-    * [PARQUET-782] - C++: Support writing to Arrow sinks
-    * [PARQUET-849] - [C++] Upgrade default Thrift in thirdparty toolchain to 0.9.3 or 0.10
-    * [PARQUET-573] - C++: Create a public API for reading and writing file metadata
-
-## Task
-    * [PARQUET-814] - C++: Remove Conda recipes
-    * [PARQUET-503] - Re-enable parquet 2.0 encodings
-    * [PARQUET-169] - Parquet-cpp: Implement support for bulk reading and writing repetition/definition levels.
-    * [PARQUET-878] - C++: Remove setup_build_env from rc-verification script
-    * [PARQUET-881] - C++: Update Arrow hash to 0.2.0-rc2
-    * [PARQUET-771] - C++: Sync KEYS file
-    * [PARQUET-901] - C++: Publish RCs in apache-parquet-VERSION in SVN
-
-## Test
-    * [PARQUET-525] - Test coverage for malformed file failure modes on the read path
-    * [PARQUET-703] - [C++] Validate num_values metadata for columns with nulls
-    * [PARQUET-507] - Improve runtime of rle-test.cc
-    * [PARQUET-549] - Add scanner and column reader tests for dictionary data pages
-    * [PARQUET-457] - Add compressed data page unit tests
-
-
diff --git a/CMakeLists.txt b/CMakeLists.txt
deleted file mode 100644
index fa4fb21..0000000
--- a/CMakeLists.txt
+++ /dev/null
@@ -1,783 +0,0 @@
-# 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.
-
-# Require cmake that supports BYPRODUCTS in add_custom_command, ExternalProject_Add [1].
-cmake_minimum_required(VERSION 3.2.0)
-
-message(FATAL_ERROR "Building parquet-cpp master is no longer supported. "
-  "Build from C++ codebase in https://github.com/apache/arrow with -DARROW_PARQUET=ON")
-
-file(READ "${CMAKE_CURRENT_SOURCE_DIR}/.parquetcppversion" PARQUET_VERSION)
-string(REPLACE "\n" "" PARQUET_VERSION "${PARQUET_VERSION}")
-string(REGEX MATCH "^([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?)" VERSION ${PARQUET_VERSION})
-if(NOT VERSION)
-  message(FATAL_ERROR "invalid .parquetcppversion")
-endif()
-
-project(parquet-cpp VERSION ${VERSION})
-set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "C++ library to read and write the Apache Parquet columnar data format")
-set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
-set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
-set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
-set(CPACK_PACKAGE_VENDOR        "Apache Software Foundation")
-set(CPACK_PACKAGE_CONTACT       "Apache Parquet Development <dev@parquet.apache.org>")
-set(CPACK_STRIP_FILES           TRUE)
-set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE.txt")
-set(CPACK_DEBIAN_FILE_NAME      "DEB-DEFAULT")
-set(CPACK_RPM_FILE_NAME         "RPM-DEFAULT")
-set(CPACK_RPM_PACKAGE_LICENSE   "Apache v2.0")
-
-include(ExternalProject)
-include(FindPkgConfig)
-
-# This ensures that things like gnu++11 get passed correctly
-set(CMAKE_CXX_STANDARD 11)
-
-# We require a C++11 compliant compiler
-set(CMAKE_CXX_STANDARD_REQUIRED ON)
-
-include(GNUInstallDirs)
-
-set(PARQUET_SO_VERSION ${PROJECT_VERSION_MAJOR})
-set(PARQUET_ABI_VERSION ${PROJECT_VERSION})
-if(WIN32)
-  set(INSTALL_CMAKE_DIR cmake)
-else()
-  set(INSTALL_CMAKE_DIR "${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake")
-endif()
-set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/usr/${CMAKE_INSTALL_LIBDIR}/pkgconfig")
-include(CPack)
-
-include(CMakePackageConfigHelpers)
-configure_package_config_file(cmake_modules/${PROJECT_NAME}Config.cmake.in
-                              ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
-                              INSTALL_DESTINATION ${INSTALL_CMAKE_DIR}
-                              PATH_VARS CMAKE_INSTALL_INCLUDEDIR CMAKE_INSTALL_LIBDIR)
-write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
-                                 COMPATIBILITY SameMajorVersion)
-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
-              ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
-DESTINATION ${INSTALL_CMAKE_DIR})
-
-if (NOT "$ENV{PARQUET_GCC_ROOT}" STREQUAL "")
-  set(GCC_ROOT $ENV{PARQUET_GCC_ROOT})
-  set(CMAKE_C_COMPILER ${GCC_ROOT}/bin/gcc)
-  set(GCOV_PATH ${GCC_ROOT}/bin/gcov)
-  set(CMAKE_CXX_COMPILER ${GCC_ROOT}/bin/g++)
-endif()
-
-# generate CTest input files
-enable_testing()
-
-# where to find cmake modules
-set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake_modules")
-set(BUILD_SUPPORT_DIR "${CMAKE_SOURCE_DIR}/build-support")
-
-set(CLANG_FORMAT_VERSION "6.0")
-find_package(ClangTools)
-if ("$ENV{CMAKE_EXPORT_COMPILE_COMMANDS}" STREQUAL "1" OR CLANG_TIDY_FOUND)
-  # Generate a Clang compile_commands.json "compilation database" file for use
-  # with various development tools, such as Vim's YouCompleteMe plugin.
-  # See http://clang.llvm.org/docs/JSONCompilationDatabase.html
-  set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
-endif()
-
-find_program(CCACHE_FOUND ccache)
-if(CCACHE_FOUND)
-  set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
-  set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
-endif(CCACHE_FOUND)
-
-if(APPLE)
-  set(CMAKE_MACOSX_RPATH 1)
-endif()
-
-# if no build build type is specified, default to debug builds
-if (NOT CMAKE_BUILD_TYPE)
-  set(CMAKE_BUILD_TYPE Debug)
-endif(NOT CMAKE_BUILD_TYPE)
-
-# set compile output directory
-string (TOLOWER ${CMAKE_BUILD_TYPE} BUILD_SUBDIR_NAME)
-
-# Top level cmake file, set options
-if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
-  option(PARQUET_BUILD_SHARED
-    "Build the shared version of libparquet"
-    ON)
-  option(PARQUET_BUILD_STATIC
-    "Build the static version of libparquet. Always ON if building unit tests"
-    ON)
-  set(PARQUET_ARROW_LINKAGE "shared" CACHE STRING
-    "Libraries to link for Apache Arrow. static|shared (default shared)")
-  set(PARQUET_CXXFLAGS "" CACHE STRING
-    "Compiler flags to use when compiling Parquet")
-  option(PARQUET_USE_SSE
-    "Build with SSE4 optimizations"
-    OFF)
-  option(PARQUET_BUILD_BENCHMARKS
-    "Build the libparquet benchmark suite"
-    OFF)
-
-  set(PARQUET_BUILD_WARNING_LEVEL "PRODUCTION" CACHE STRING
-    "Levels of compiler warnings for development: PRODUCTION/CHECKIN/EVERYTHING")
-
-  option(PARQUET_BOOST_USE_SHARED
-    "Rely on boost shared libraries where relevant"
-    ON)
-  option(PARQUET_BUILD_TESTS
-    "Build the libparquet test suite"
-    ON)
-  option(PARQUET_TEST_MEMCHECK
-    "Run the test suite using valgrind --tool=memcheck"
-    OFF)
-  option(PARQUET_BUILD_EXECUTABLES
-    "Build the libparquet executable CLI tools"
-    ON)
-  option(PARQUET_RPATH_ORIGIN
-    "Build Parquet libraries with RPATH set to \$ORIGIN"
-    OFF)
-  option(PARQUET_MINIMAL_DEPENDENCY
-    "Depend only on Thirdparty headers to build libparquet. Always OFF if building binaries"
-    OFF)
-
-  option(PARQUET_THRIFT_USE_BOOST
-    "Enable if Thirdparty Thrift uses boost::shared_ptr (Apache Thrift < 0.11)"
-    OFF)
-
-  if (MSVC)
-    set(ARROW_MSVC_STATIC_LIB_SUFFIX "_static" CACHE STRING
-      "Arrow static lib suffix used on Windows with MSVC (default _static)")
-    set(THRIFT_MSVC_STATIC_LIB_SUFFIX "md" CACHE STRING
-      "Thrift static lib suffix used on Windows with MSVC (default md)")
-    option(PARQUET_USE_STATIC_CRT
-      "Build Parquet with statically linked CRT"
-      OFF)
-    option(PARQUET_USE_CLCACHE
-      "Use clcache if available"
-      ON)
-  endif()
-
-  option(PARQUET_VERBOSE_THIRDPARTY_BUILD
-    "If off, output from ExternalProjects will be logged to files rather than shown"
-    OFF)
-
-endif()
-
-if (MSVC AND PARQUET_USE_CLCACHE AND
-     (("${CMAKE_GENERATOR}" STREQUAL "NMake Makefiles") OR
-      ("${CMAKE_GENERATOR}" STREQUAL "Ninja")))
-  find_program(CLCACHE_FOUND clcache)
-  if(CLCACHE_FOUND)
-    set(CMAKE_CXX_COMPILER ${CLCACHE_FOUND})
-  endif(CLCACHE_FOUND)
-endif()
-
-include(BuildUtils)
-
-if (PARQUET_BUILD_TESTS OR PARQUET_BUILD_EXECUTABLES OR PARQUET_BUILD_BENCHMARKS)
-  set(PARQUET_BUILD_STATIC ON)
-  set(PARQUET_MINIMAL_DEPENDENCY OFF)
-endif()
-
-# If build in-source, create the latest symlink. If build out-of-source, which is
-# preferred, simply output the binaries in the build folder
-if (${CMAKE_SOURCE_DIR} STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
-  set(BUILD_OUTPUT_ROOT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/build/${BUILD_SUBDIR_NAME}")
-  # Link build/latest to the current build directory, to avoid developers
-  # accidentally running the latest debug build when in fact they're building
-  # release builds.
-  FILE(MAKE_DIRECTORY ${BUILD_OUTPUT_ROOT_DIRECTORY})
-  if (NOT APPLE)
-    set(MORE_ARGS "-T")
-  endif()
-EXECUTE_PROCESS(COMMAND ln ${MORE_ARGS} -sf ${BUILD_OUTPUT_ROOT_DIRECTORY}
-  ${CMAKE_CURRENT_BINARY_DIR}/build/latest)
-else()
-  set(BUILD_OUTPUT_ROOT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${BUILD_SUBDIR_NAME}")
-endif()
-
-# where to put generated archives (.a files)
-set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${BUILD_OUTPUT_ROOT_DIRECTORY}")
-set(ARCHIVE_OUTPUT_DIRECTORY "${BUILD_OUTPUT_ROOT_DIRECTORY}")
-
-# where to put generated libraries (.so files)
-set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${BUILD_OUTPUT_ROOT_DIRECTORY}")
-set(LIBRARY_OUTPUT_DIRECTORY "${BUILD_OUTPUT_ROOT_DIRECTORY}")
-
-# where to put generated binaries
-set(EXECUTABLE_OUTPUT_PATH "${BUILD_OUTPUT_ROOT_DIRECTORY}")
-
-if (MSVC)
-  # define output directories to overwrite default Visual Studio generator output directories
-  FOREACH(BUILD_CONFIG ${CMAKE_CONFIGURATION_TYPES})
-    string(TOUPPER ${BUILD_CONFIG} UPPERCASE_BUILD_CONFIG)
-    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${UPPERCASE_BUILD_CONFIG} ${BUILD_OUTPUT_ROOT_DIRECTORY})
-    set(CMAKE_PDB_OUTPUT_DIRECTORY_${UPPERCASE_BUILD_CONFIG} ${BUILD_OUTPUT_ROOT_DIRECTORY})
-    set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${UPPERCASE_BUILD_CONFIG} ${BUILD_OUTPUT_ROOT_DIRECTORY})
-    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${UPPERCASE_BUILD_CONFIG} ${BUILD_OUTPUT_ROOT_DIRECTORY})
-  ENDFOREACH()
-endif()
-
-############################################################
-# Benchmarking
-############################################################
-# Add a new micro benchmark, with or without an executable that should be built.
-# If benchmarks are enabled then they will be run along side unit tests with ctest.
-# 'make runbenchmark' and 'make unittest' to build/run only benchmark or unittests,
-# respectively.
-#
-# REL_BENCHMARK_NAME is the name of the benchmark app. It may be a single component
-# (e.g. monotime-benchmark) or contain additional components (e.g.
-# net/net_util-benchmark). Either way, the last component must be a globally
-# unique name.
-
-# The benchmark will registered as unit test with ctest with a label
-# of 'benchmark'.
-#
-# Arguments after the test name will be passed to set_tests_properties().
-function(ADD_PARQUET_BENCHMARK REL_BENCHMARK_NAME)
-  if(NOT PARQUET_BUILD_BENCHMARKS)
-    return()
-  endif()
-  get_filename_component(BENCHMARK_NAME ${REL_BENCHMARK_NAME} NAME_WE)
-
-  if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${REL_BENCHMARK_NAME}.cc)
-    # This benchmark has a corresponding .cc file, set it up as an executable.
-    set(BENCHMARK_PATH "${EXECUTABLE_OUTPUT_PATH}/${BENCHMARK_NAME}")
-    add_executable(${BENCHMARK_NAME} "${REL_BENCHMARK_NAME}.cc")
-
-    if(APPLE)
-      # On OS X / Thrift >= 0.9.2, tr1/tuple.h is not in libc++
-      SET_TARGET_PROPERTIES(${TEST_NAME} PROPERTIES COMPILE_FLAGS
-        -DGTEST_USE_OWN_TR1_TUPLE=1)
-    else()
-      # Linux, for Thrift >= 0.9.2
-      SET_TARGET_PROPERTIES(${TEST_NAME} PROPERTIES COMPILE_FLAGS
-        -DGTEST_USE_OWN_TR1_TUPLE=0)
-    endif()
-
-    target_link_libraries(${BENCHMARK_NAME} ${PARQUET_BENCHMARK_LINK_LIBS})
-    add_dependencies(runbenchmark ${BENCHMARK_NAME})
-    set(NO_COLOR "--color_print=false")
-  else()
-    # No executable, just invoke the benchmark (probably a script) directly.
-    set(BENCHMARK_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${REL_BENCHMARK_NAME})
-    set(NO_COLOR "")
-  endif()
-
-  if(WIN32)
-    add_test(${BENCHMARK_NAME} ${BENCHMARK_PATH} ${NO_COLOR})
-  else()
-    add_test(${BENCHMARK_NAME}
-      ${BUILD_SUPPORT_DIR}/run-test.sh ${CMAKE_BINARY_DIR} benchmark ${BENCHMARK_PATH} ${NO_COLOR})
-  endif()
-  set_tests_properties(${BENCHMARK_NAME} PROPERTIES LABELS "benchmark")
-  if(ARGN)
-    set_tests_properties(${BENCHMARK_NAME} PROPERTIES ${ARGN})
-  endif()
-endfunction()
-
-# A wrapper for add_dependencies() that is compatible with NO_BENCHMARKS.
-function(ADD_PARQUET_BENCHMARK_DEPENDENCIES REL_BENCHMARK_NAME)
-  if(NOT PARQUET_BUILD_BENCHMARKS)
-    return()
-  endif()
-  get_filename_component(BENCMARK_NAME ${REL_BENCHMARK_NAME} NAME_WE)
-
-  add_dependencies(${BENCHMARK_NAME} ${ARGN})
-endfunction()
-
-############################################################
-# Testing
-############################################################
-
-# Add a new test case, with or without an executable that should be built.
-#
-# REL_TEST_NAME is the name of the test. It may be a single component
-# (e.g. monotime-test) or contain additional components (e.g.
-# net/net_util-test). Either way, the last component must be a globally
-# unique name.
-#
-# The unit test is added with a label of "unittest" to support filtering with
-# ctest.
-#
-# Arguments after the test name will be passed to set_tests_properties().
-function(ADD_PARQUET_TEST REL_TEST_NAME)
-  set(options)
-  set(one_value_args LINKAGE)
-  set(multi_value_args)
-  cmake_parse_arguments(ARG "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN})
-
-  if(NOT PARQUET_BUILD_TESTS)
-    return()
-  endif()
-
-  # TODO(wesm): not very rigorous error checking
-  if (ARG_LINKAGE AND "${ARG_LINKAGE}" STREQUAL "shared")
-    if(NOT PARQUET_BUILD_SHARED)
-      # Skip this test if we are not building the shared library
-      return()
-    else()
-      set(TEST_LINK_LIBS ${PARQUET_TEST_SHARED_LINK_LIBS})
-    endif()
-  else()
-    set(TEST_LINK_LIBS ${PARQUET_TEST_LINK_LIBS})
-  endif()
-
-  get_filename_component(TEST_NAME ${REL_TEST_NAME} NAME_WE)
-
-  if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${REL_TEST_NAME}.cc)
-    # This test has a corresponding .cc file, set it up as an executable.
-    set(TEST_PATH "${EXECUTABLE_OUTPUT_PATH}/${TEST_NAME}")
-    add_executable(${TEST_NAME} "${REL_TEST_NAME}.cc")
-    add_dependencies(unittest ${TEST_NAME})
-
-    if(APPLE)
-      # On OS X / Thrift >= 0.9.2, tr1/tuple.h is not in libc++
-      SET_TARGET_PROPERTIES(${TEST_NAME} PROPERTIES COMPILE_FLAGS
-        -DGTEST_USE_OWN_TR1_TUPLE=1)
-    else()
-      # Linux, for Thrift >= 0.9.2
-      SET_TARGET_PROPERTIES(${TEST_NAME} PROPERTIES COMPILE_FLAGS
-        -DGTEST_USE_OWN_TR1_TUPLE=0)
-    endif()
-
-    target_link_libraries(${TEST_NAME} ${TEST_LINK_LIBS})
-  else()
-    # No executable, just invoke the test (probably a script) directly.
-    set(TEST_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${REL_TEST_NAME})
-  endif()
-
-  if (PARQUET_TEST_MEMCHECK)
-    SET_PROPERTY(TARGET ${TEST_NAME}
-      APPEND_STRING PROPERTY
-      COMPILE_FLAGS " -DPARQUET_VALGRIND")
-    add_test(${TEST_NAME}
-      valgrind --tool=memcheck --leak-check=full --error-exitcode=1 ${TEST_PATH})
-  elseif(MSVC)
-    add_test(${TEST_NAME} ${TEST_PATH})
-  else()
-    add_test(${TEST_NAME}
-        ${BUILD_SUPPORT_DIR}/run-test.sh ${CMAKE_BINARY_DIR} test ${TEST_PATH})
-  endif()
-  set_tests_properties(${TEST_NAME} PROPERTIES LABELS "unittest")
-  if(ARGN)
-    set_tests_properties(${TEST_NAME} PROPERTIES ${ARGN})
-  endif()
-endfunction()
-
-# A wrapper for add_dependencies() that is compatible with PARQUET_BUILD_TESTS.
-function(ADD_PARQUET_TEST_DEPENDENCIES REL_TEST_NAME)
-  if(NOT PARQUET_BUILD_TESTS)
-    return()
-  endif()
-  get_filename_component(TEST_NAME ${REL_TEST_NAME} NAME_WE)
-
-  add_dependencies(${TEST_NAME} ${ARGN})
-endfunction()
-
-# A wrapper for add_dependencies() that is compatible with PARQUET_BUILD_TESTS.
-function(ADD_PARQUET_LINK_LIBRARIES REL_TEST_NAME)
-  if(NOT PARQUET_BUILD_TESTS)
-    return()
-  endif()
-  get_filename_component(TEST_NAME ${REL_TEST_NAME} NAME_WE)
-
-  target_link_libraries(${TEST_NAME} ${ARGN})
-endfunction()
-
-enable_testing()
-
-############################################################
-# Dependencies
-############################################################
-
-# Determine compiler version
-include(CompilerInfo)
-include(SetupCxxFlags)
-
-include_directories(${CMAKE_CURRENT_BINARY_DIR}/src)
-include_directories(
-  ${CMAKE_CURRENT_SOURCE_DIR}/src
-)
-
-if (PARQUET_MINIMAL_DEPENDENCY)
-    set(IGNORE_OPTIONAL_PACKAGES ON)
-    message(STATUS "Build using minimal dependencies")
-else()
-    set(IGNORE_OPTIONAL_PACKAGES OFF)
-endif()
-include(ThirdpartyToolchain)
-
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_COMMON_FLAGS}")
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PARQUET_CXXFLAGS}")
-
-message(STATUS "CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}")
-
-# Thrift requires these definitions for some types that we use
-add_definitions(-DHAVE_INTTYPES_H -DHAVE_NETDB_H)
-if (MSVC)
-  add_definitions(-DNOMINMAX -D_CRT_SECURE_NO_WARNINGS)
-else()
-  add_definitions(-DHAVE_NETINET_IN_H -fPIC)
-endif()
-
-############################################################
-# "make lint" target
-############################################################
-if (UNIX)
-  find_program(CPPLINT_BIN NAMES cpplint cpplint.py HINTS ${BUILD_SUPPORT_DIR})
-  message(STATUS "Found cpplint executable at ${CPPLINT_BIN}")
-  # Full lint
-  add_custom_target(lint ${CPPLINT_BIN}
-  --verbose=2
-  --linelength=90
-  --filter=-whitespace/comments,-readability/todo,-build/header_guard,-runtime/references,-readability/check,-build/c++11,-build/include_order
-    `find ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/tools ${CMAKE_CURRENT_SOURCE_DIR}/examples  ${CMAKE_CURRENT_SOURCE_DIR}/benchmarks -name \\*.cc -or -name \\*.h | sed -e '/parquet\\/parquet_/g'`)
-endif (UNIX)
-
-############################################################
-# "make format" and "make check-format" targets
-############################################################
-
-# runs clang format and updates files in place.
-add_custom_target(format-example
-  COMMAND
-  ${BUILD_SUPPORT_DIR}/run_clang_format.py
-  ${CLANG_FORMAT_BIN}
-  ${BUILD_SUPPORT_DIR}/clang_format_exclusions.txt
-  ${CMAKE_CURRENT_SOURCE_DIR}/examples)
-
-add_custom_target(format
-  DEPENDS format-example
-  COMMAND
-  ${BUILD_SUPPORT_DIR}/run_clang_format.py
-  ${CLANG_FORMAT_BIN}
-  ${BUILD_SUPPORT_DIR}/clang_format_exclusions.txt
-  ${CMAKE_CURRENT_SOURCE_DIR}/src)
-
-# runs clang format and exits with a non-zero exit code if any files need to be reformatted
-
-# TODO(wesm): Make this work in run_clang_format.py
-add_custom_target(check-format-examples ${BUILD_SUPPORT_DIR}/run_clang_format.py
-   ${CLANG_FORMAT_BIN}
-   ${BUILD_SUPPORT_DIR}/clang_format_exclusions.txt
-   ${CMAKE_CURRENT_SOURCE_DIR}/examples 1)
-add_custom_target(check-format
-   DEPENDS check-format-examples
-   COMMAND
-   ${BUILD_SUPPORT_DIR}/run_clang_format.py
-   ${CLANG_FORMAT_BIN}
-   ${BUILD_SUPPORT_DIR}/clang_format_exclusions.txt
-   ${CMAKE_CURRENT_SOURCE_DIR}/src 1)
-
-############################################################
-# "make clang-tidy" and "make check-clang-tidy" targets
-############################################################
-
-if (${CLANG_TIDY_FOUND})
-  # runs clang-tidy and attempts to fix any warning automatically
-  add_custom_target(clang-tidy ${BUILD_SUPPORT_DIR}/run-clang-tidy.sh ${CLANG_TIDY_BIN} ${CMAKE_BINARY_DIR}/compile_commands.json 1
-  `find ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/tools  ${CMAKE_CURRENT_SOURCE_DIR}/examples ${CMAKE_CURRENT_SOURCE_DIR}/benchmarks -name \\*.cc | sed -e '/_types/g' | sed -e '/_constants/g'`)
-  # runs clang-tidy and exits with a non-zero exit code if any errors are found.
-  add_custom_target(check-clang-tidy ${BUILD_SUPPORT_DIR}/run-clang-tidy.sh ${CLANG_TIDY_BIN} ${CMAKE_BINARY_DIR}/compile_commands.json
-  0 `find ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/tools  ${CMAKE_CURRENT_SOURCE_DIR}/examples ${CMAKE_CURRENT_SOURCE_DIR}/benchmarks -name \\*.cc |grep -v -F -f ${CMAKE_CURRENT_SOURCE_DIR}/.clang-tidy-ignore`)
-
-endif()
-
-#############################################################
-# Code coverage
-
-# Adapted from Apache Kudu (incubating)
-if ("${PARQUET_GENERATE_COVERAGE}")
-  if("${CMAKE_CXX_COMPILER}" MATCHES ".*clang.*")
-    # There appears to be some bugs in clang 3.3 which cause code coverage
-    # to have link errors, not locating the llvm_gcda_* symbols.
-    # This should be fixed in llvm 3.4 with http://llvm.org/viewvc/llvm-project?view=revision&revision=184666
-    message(SEND_ERROR "Cannot currently generate coverage with clang")
-  endif()
-  message(STATUS "Configuring build for gcov")
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage")
-  # For coverage to work properly, we need to use static linkage. Otherwise,
-  # __gcov_flush() doesn't properly flush coverage from every module.
-  # See http://stackoverflow.com/questions/28164543/using-gcov-flush-within-a-library-doesnt-force-the-other-modules-to-yield-gc
-  if(NOT PARQUET_BUILD_STATIC)
-    message(SEND_ERROR "Coverage requires the static lib to be built")
-  endif()
-endif()
-
-#############################################################
-# Boost linkage
-
-if (PARQUET_BOOST_USE_SHARED)
-  set(BOOST_LINK_LIBS
-    boost_shared_regex)
-  if(MSVC)
-    set(BOOST_LINK_LIBS ${BOOST_LINK_LIBS}
-      boost_shared_system)
-  endif()
-else()
-  set(BOOST_LINK_LIBS
-    boost_static_regex)
-  if(MSVC)
-    set(BOOST_LINK_LIBS ${BOOST_LINK_LIBS}
-      boost_static_system boost_static_filesystem)
-  endif()
-endif()
-
-#############################################################
-# Apache Arrow linkage
-
-if ("${PARQUET_ARROW_LINKAGE}" STREQUAL "shared")
-  set(ARROW_LINK_LIBS
-    arrow)
-else()
-  #############################################################
-  # Transitive Library Linkage
-
-  if (NOT DEFINED ENV{BROTLI_STATIC_LIB_ENC} OR
-      NOT DEFINED ENV{BROTLI_STATIC_LIB_DEC} OR
-      NOT DEFINED ENV{BROTLI_STATIC_LIB_COMMON} OR
-      NOT DEFINED ENV{SNAPPY_STATIC_LIB} OR
-      NOT DEFINED ENV{ZLIB_STATIC_LIB} OR
-      NOT DEFINED ENV{LZ4_STATIC_LIB} OR
-      NOT DEFINED ENV{ZSTD_STATIC_LIB})
-    message(FATAL_ERROR "Missing transitive dependencies for Arrow static linking")
-  endif()
-
-  set(BROTLI_STATIC_LIB_ENC "$ENV{BROTLI_STATIC_LIB_ENC}")
-  set(BROTLI_STATIC_LIB_DEC "$ENV{BROTLI_STATIC_LIB_DEC}")
-  set(BROTLI_STATIC_LIB_COMMON "$ENV{BROTLI_STATIC_LIB_COMMON}")
-  set(SNAPPY_STATIC_LIB "$ENV{SNAPPY_STATIC_LIB}")
-  set(ZLIB_STATIC_LIB "$ENV{ZLIB_STATIC_LIB}")
-  set(LZ4_STATIC_LIB "$ENV{LZ4_STATIC_LIB}")
-  set(ZSTD_STATIC_LIB "$ENV{ZSTD_STATIC_LIB}")
-
-  add_library(brotli_enc STATIC IMPORTED)
-  set_target_properties(brotli_enc PROPERTIES IMPORTED_LOCATION ${BROTLI_STATIC_LIB_ENC})
-  add_library(brotli_dec STATIC IMPORTED)
-  set_target_properties(brotli_dec PROPERTIES IMPORTED_LOCATION ${BROTLI_STATIC_LIB_DEC})
-  add_library(brotli_common STATIC IMPORTED)
-  set_target_properties(brotli_common PROPERTIES IMPORTED_LOCATION ${BROTLI_STATIC_LIB_COMMON})
-  add_library(snappy STATIC IMPORTED)
-  set_target_properties(snappy PROPERTIES IMPORTED_LOCATION ${SNAPPY_STATIC_LIB})
-  add_library(zlib STATIC IMPORTED)
-  set_target_properties(zlib PROPERTIES IMPORTED_LOCATION ${ZLIB_STATIC_LIB})
-  add_library(lz4 STATIC IMPORTED)
-  set_target_properties(lz4 PROPERTIES IMPORTED_LOCATION ${LZ4_STATIC_LIB})
-  add_library(zstd STATIC IMPORTED)
-  set_target_properties(zstd PROPERTIES IMPORTED_LOCATION ${ZSTD_STATIC_LIB})
-
-  set(TRANSITIVE_LINK_LIBS
-    snappy
-    zlib
-    brotli_enc
-    brotli_dec
-    brotli_common
-    lz4
-    zstd
-  )
-
-  add_definitions(-DARROW_STATIC)
-
-  set(ARROW_LINK_LIBS
-    arrow_static
-    ${TRANSITIVE_LINK_LIBS})
-endif()
-
-#############################################################
-# Test linking
-
-set(PARQUET_MIN_TEST_LIBS
-  gtest
-  gtest_main)
-
-if (APPLE)
-  set(PARQUET_MIN_TEST_LIBS
-    ${PARQUET_MIN_TEST_LIBS}
-    ${CMAKE_DL_LIBS})
-elseif(NOT MSVC)
-  set(PARQUET_MIN_TEST_LIBS
-    ${PARQUET_MIN_TEST_LIBS}
-    pthread
-    ${CMAKE_DL_LIBS})
-endif()
-
-set(PARQUET_TEST_LINK_LIBS ${PARQUET_MIN_TEST_LIBS}
-  ${ARROW_LINK_LIBS}
-  parquet_static)
-
-set(PARQUET_TEST_SHARED_LINK_LIBS ${PARQUET_MIN_TEST_LIBS}
-  parquet_shared)
-
-#############################################################
-# Benchmark linking
-
-if (PARQUET_BUILD_STATIC)
-    set(PARQUET_BENCHMARK_LINK_LIBS
-      parquet_benchmark_main
-      parquet_static)
-else()
-    set(PARQUET_BENCHMARK_LINK_LIBS
-      parquet_benchmark_main
-      parquet_shared)
-endif()
-
-############################################################
-# Generated Thrift sources
-
-set(THRIFT_SRCS
-  src/parquet/parquet_constants.cpp
-  src/parquet/parquet_types.cpp)
-
-if (NOT MSVC)
-  set_source_files_properties(src/parquet/parquet_types.cpp PROPERTIES
-    COMPILE_FLAGS -Wno-unused-variable)
-endif()
-
-# List of thrift output targets
-set(THRIFT_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/src/parquet)
-set(THRIFT_OUTPUT_FILES "${THRIFT_OUTPUT_DIR}/parquet_types.cpp")
-set(THRIFT_OUTPUT_FILES ${THRIFT_OUTPUT_FILES} "${THRIFT_OUTPUT_DIR}/parquet_types.h")
-set(THRIFT_OUTPUT_FILES ${THRIFT_OUTPUT_FILES} "${THRIFT_OUTPUT_DIR}/parquet_constants.cpp")
-set(THRIFT_OUTPUT_FILES ${THRIFT_OUTPUT_FILES} "${THRIFT_OUTPUT_DIR}/parquet_constants.h")
-
-set_source_files_properties(${THRIFT_OUTPUT_FILES} PROPERTIES GENERATED TRUE)
-
-get_filename_component(ABS_PARQUET_THRIFT src/parquet/parquet.thrift ABSOLUTE)
-
-add_custom_command(
-  OUTPUT ${THRIFT_OUTPUT_FILES}
-  COMMAND ${THRIFT_COMPILER} --gen cpp -out ${THRIFT_OUTPUT_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/src/parquet/parquet.thrift
-  DEPENDS ${ABS_PARQUET_THRIFT} thriftstatic
-  COMMENT "Running thrift compiler on parquet.thrift"
-  VERBATIM
-)
-
-############################################################
-# Library config
-
-set(LIBPARQUET_SRCS
-  src/parquet/arrow/reader.cc
-  src/parquet/arrow/record_reader.cc
-  src/parquet/arrow/schema.cc
-  src/parquet/arrow/writer.cc
-  src/parquet/bloom_filter.cc
-  src/parquet/column_reader.cc
-  src/parquet/column_scanner.cc
-  src/parquet/column_writer.cc
-  src/parquet/exception.cc
-  src/parquet/file_reader.cc
-  src/parquet/file_writer.cc
-  src/parquet/metadata.cc
-  src/parquet/murmur3.cc
-  src/parquet/parquet_constants.cpp
-  src/parquet/parquet_types.cpp
-  src/parquet/printer.cc
-  src/parquet/schema.cc
-  src/parquet/statistics.cc
-  src/parquet/types.cc
-  src/parquet/util/comparison.cc
-  src/parquet/util/memory.cc
-)
-
-# # Ensure that thrift compilation is done before using its generated headers
-# # in parquet code.
-add_custom_target(thrift-deps ALL
-  DEPENDS ${THRIFT_OUTPUT_FILES})
-set(PARQUET_DEPENDENCIES ${PARQUET_DEPENDENCIES} thrift-deps)
-
-if (NOT PARQUET_MINIMAL_DEPENDENCY)
-# These are libraries that we will link privately with parquet_shared (as they
-# do not need to be linked transitively by other linkers), but publicly with
-# parquet_static (because internal users need to transitively link all
-# dependencies)
-  set(LIBPARQUET_INTERFACE_LINK_LIBS
-    ${ARROW_LINK_LIBS}
-    ${BOOST_LINK_LIBS}
-    thriftstatic
-  )
-# Although we don't link parquet_objlib against anything, we need it to depend
-# on these libs as we may generate their headers via ExternalProject_Add
-  set(PARQUET_DEPENDENCIES ${PARQUET_DEPENDENCIES} ${LIBPARQUET_INTERFACE_LINK_LIBS})
-endif()
-
-if(NOT APPLE AND NOT MSVC)
-  # Localize thirdparty symbols using a linker version script. This hides them
-  # from the client application. The OS X linker does not support the
-  # version-script option.
-  set(SHARED_LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/src/parquet/symbols.map")
-endif()
-
-ADD_LIB(parquet
-        SOURCES ${LIBPARQUET_SRCS}
-        LIB_BUILD_SHARED ${PARQUET_BUILD_SHARED}
-        LIB_BUILD_STATIC ${PARQUET_BUILD_STATIC}
-        DEPENDENCIES ${PARQUET_DEPENDENCIES}
-        SHARED_LINK_FLAGS ${SHARED_LINK_FLAGS}
-        SHARED_PRIVATE_LINK_LIBS ${LIBPARQUET_INTERFACE_LINK_LIBS}
-        STATIC_LINK_LIBS ${LIBPARQUET_INTERFACE_LINK_LIBS}
-        ABI_VERSION ${PARQUET_ABI_VERSION}
-        SO_VERSION ${PARQUET_SO_VERSION}
-)
-
-############################################################
-# Visibility
-############################################################
-# For generate_export_header() and add_compiler_export_flags().
-include(GenerateExportHeader)
-
-# Adapted from Apache Kudu: https://github.com/apache/kudu/commit/bd549e13743a51013585
-# Honor visibility properties for all target types. See
-# "cmake --help-policy CMP0063" for details.
-#
-# This policy was only added to cmake in version 3.3, so until the cmake in
-# thirdparty is updated, we must check if the policy exists before setting it.
-if(POLICY CMP0063)
-  cmake_policy(SET CMP0063 NEW)
-endif()
-
-if (PARQUET_BUILD_SHARED)
-  if (POLICY CMP0063)
-    set_target_properties(parquet_shared
-      PROPERTIES C_VISIBILITY_PRESET hidden)
-    set_target_properties(parquet_shared
-      PROPERTIES CXX_VISIBILITY_PRESET hidden)
-    set_target_properties(parquet_shared
-      PROPERTIES VISIBILITY_INLINES_HIDDEN 1)
-  else()
-    # Sets -fvisibility=hidden for gcc
-    add_compiler_export_flags()
-  endif()
-endif()
-
-add_subdirectory(src/parquet)
-add_subdirectory(src/parquet/api)
-add_subdirectory(src/parquet/arrow)
-add_subdirectory(src/parquet/util)
-
-if (NOT MSVC)
-  add_subdirectory(benchmarks)
-endif()
-add_subdirectory(examples/low-level-api)
-add_subdirectory(tools)
-
-add_custom_target(clean-all
-   COMMAND ${CMAKE_BUILD_TOOL} clean
-   COMMAND ${CMAKE_COMMAND} -P cmake_modules/clean-all.cmake
-)
diff --git a/NOTICE.txt b/NOTICE.txt
deleted file mode 100644
index a1ab98e..0000000
--- a/NOTICE.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Apache Parquet
-Copyright 2016 The Apache Software Foundation
-
-This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
diff --git a/README.md b/README.md
index a42e7b4..cf0c62f 100644
--- a/README.md
+++ b/README.md
@@ -12,271 +12,11 @@
   limitations under the License. See accompanying LICENSE file.
 -->
 
-## Note: Development for Apache Parquet in C++ has moved
+# Note: Development for Apache Parquet in C++ has moved
 
-The Apache Arrow and Parquet have merged development process and build systems
-in the Arrow repository. Please submit pull requests in
+The Apache Arrow and Parquet C++ projects have merged development process and
+build systems in the Arrow repository. Please submit pull requests in
 https://github.com/apache/arrow.
 
 JIRA issues should continue to be opened in the PARQUET JIRA project.
-
-## Apache Parquet for C++: a C++ library to read and write the Apache Parquet
-   columnar data format.
-
-<table>
-  <tr>
-    <td>Build Status</td>
-    <td>
-    <a href="https://travis-ci.org/apache/parquet-cpp">
-    <img src="https://travis-ci.org/apache/parquet-cpp.svg?branch=master" alt="travis build status" />
-    </a>
-    </td>
-  </tr>
-  <tr>
-    <td>Test coverage</td>
-    <td>
-      <a href='https://coveralls.io/github/apache/parquet-cpp?branch=master'><img src='https://coveralls.io/repos/github/apache/parquet-cpp/badge.svg?branch=master' alt='Coverage Status' /></a>
-    </td>
-  </tr>
-</table>
-
-## System Dependencies
-
-We use the CMake build system and require a minimum version of 3.2. If you are
-using an older Linux distribution, you may need to use a PPA (for apt users) or
-build CMake from source.
-
-### Linux
-
-parquet-cpp requires gcc 4.8 or higher on Linux.
-
-To build parquet-cpp out of the box, you must install some build prerequisites
-for the thirdparty dependencies. On Debian/Ubuntu, these can be installed with:
-
-```
-sudo apt-get install libboost-dev libboost-filesystem-dev \
-                     libboost-program-options-dev libboost-regex-dev \
-                     libboost-system-dev libboost-test-dev \
-                     libssl-dev libtool bison flex pkg-config
-```
-
-### OS X
-
-You must use XCode 6 or higher. We recommend using Homebrew to install Boost,
-which is required for Thrift:
-
-```
-brew install boost
-```
-
-### Windows
-
-Check [Windows developer guide][1] for instructions to build parquet-cpp on Windows.
-
-## Third Party Dependencies
-
-- Apache Arrow >= 0.7.0 (memory management, compression, IO, optional columnar
-  data adapters)
-- Thrift 0.7+ [install instructions](https://thrift.apache.org/docs/install/)
-- googletest 1.7.0 (cannot be installed with package managers)
-- Google Benchmark (only required if building benchmarks)
-
-You can either install these dependencies separately, otherwise they will be
-built automatically as part of the build.
-
-Symbols from Thrift, Snappy, and ZLib are statically-linked into the
-`libparquet` shared library, so these dependencies must be built with `-fPIC`
-on Linux and OS X. Since Linux package managers do not consistently compile the
-static libraries for these components with `-fPIC`, you may have issues with
-Linux packages such as `libsnappy-dev`. It may be easier to depend on the
-thirdparty toolchain that parquet-cpp builds automatically.
-
-## Build
-
-- `cmake .`
-
-  - You can customize build dependency locations through various environment variables:
-    - ARROW_HOME customizes the Apache Arrow installed location.
-    - THRIFT_HOME customizes the Apache Thrift (C++ libraries and compiler
-      installed location.
-    - GTEST_HOME customizes the googletest installed location (if you are
-      building the unit tests).
-    - GBENCHMARK_HOME customizes the Google Benchmark installed location (if
-      you are building the benchmarks).
-
-- `make`
-
-The binaries will be built to ./debug which contains the libraries to link against as
-well as a few example executables.
-
-To disable the testing (which requires `googletest`), pass
-`-DPARQUET_BUILD_TESTS=Off` to `cmake`.
-
-For release-level builds (enable optimizations and disable debugging), pass
-`-DCMAKE_BUILD_TYPE=Release` to `cmake`.
-
-To build only the library with minimal dependencies, pass
-`-DPARQUET_MINIMAL_DEPENDENCY=ON` to `cmake`.
-Note that the executables, tests, and benchmarks should be disabled as well.
-
-Incremental builds can be done afterwords with just `make`.
-
-## Using with Apache Arrow
-
-Arrow provides some of the memory management and IO interfaces that we use in
-parquet-cpp. By default, Parquet links to Arrow's shared libraries. If you wish
-to statically-link the Arrow symbols instead, pass
-`-DPARQUET_ARROW_LINKAGE=static`.
-
-## Testing
-
-This library uses Google's `googletest` unit test framework. After building
-with `make`, you can run the test suite by running
-
-```
-make unittest
-```
-
-The test suite relies on an environment variable `PARQUET_TEST_DATA` pointing
-to the `data` directory in the source checkout, for example:
-
-```
-export PARQUET_TEST_DATA=`pwd`/data
-```
-
-See `ctest --help` for configuration details about ctest. On GNU/Linux systems,
-you can use valgrind with ctest to look for memory leaks:
-
-```
-valgrind --tool=memcheck --leak-check=yes ctest
-```
-
-## Building/Running benchmarks
-
-Follow the directions for simple build except run cmake
-with the `--PARQUET_BUILD_BENCHMARKS` parameter set correctly:
-
-    cmake -DPARQUET_BUILD_BENCHMARKS=ON ..
-
-and instead of make unittest run either `make; ctest` to run both unit tests
-and benchmarks or `make runbenchmark` to run only the benchmark tests.
-
-Benchmark logs will be placed in the build directory under `build/benchmark-logs`.
-
-
-## Out-of-source builds
-
-parquet-cpp supports out of source builds. For example:
-
-```
-mkdir test-build
-cd test-build
-cmake ..
-make
-ctest -L unittest
-```
-
-By using out-of-source builds you can preserve your current build state in case
-you need to switch to another git branch.
-
-Design
-========
-The library consists of 3 layers that map to the 3 units in the parquet format.
-
-The first is the encodings which correspond to data pages. The APIs at this level
-return single values.
-
-The second layer is the column reader which corresponds to column chunks. The APIs at
-this level return a triple: definition level, repetition level and value. It also handles
-reading pages, compression and managing encodings.
-
-The 3rd layer would handle reading/writing records.
-
-Developer Notes
-========
-The project adheres to the google coding convention:
-http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
-with two notable exceptions. We do not encourage anonymous namespaces and the line
-length is 90 characters.
-
-You can run `cpplint` through the build system with
-
-```
-make lint
-```
-
-The project prefers the use of C++ style memory management. new/delete should be used
-over malloc/free. new/delete should be avoided whenever possible by using stl/boost
-where possible. For example, scoped_ptr instead of explicit new/delete and using
-std::vector instead of allocated buffers. Currently, c++11 features are not used.
-
-For error handling, this project uses exceptions.
-
-In general, many of the APIs at the layers are interface based for extensibility. To
-minimize the cost of virtual calls, the APIs should be batch-centric. For example,
-encoding should operate on batches of values rather than a single value.
-
-## Using clang with a custom gcc toolchain
-
-Suppose you are building libraries with a thirdparty gcc toolchain (not a
-built-in system one) on Linux. To use clang for development while linking to
-the proper toolchain, you can do (for out of source builds):
-
-```shell
-export CMAKE_CLANG_OPTIONS=--gcc-toolchain=$TOOLCHAIN/gcc-4.9.2
-
-export CC=$TOOLCHAIN/llvm-3.7.0/bin/clang
-export CXX=$TOOLCHAIN/llvm-3.7.0/bin/clang++
-
-cmake -DCMAKE_CLANG_OPTIONS=$CMAKE_CLANG_OPTIONS \
-	  -DCMAKE_CXX_FLAGS="-Werror" ..
-```
-
-## Code Coverage
-
-To build with `gcov` code coverage and upload results to http://coveralls.io or
-http://codecov.io, here are some instructions.
-
-First, build the project with coverage and run the test suite
-
-```
-cd $PARQUET_HOME
-mkdir coverage-build
-cd coverage-build
-cmake -DPARQUET_GENERATE_COVERAGE=1
-make -j$PARALLEL
-ctest -L unittest
-```
-
-The `gcov` artifacts are not located in a place that works well with either
-coveralls or codecov, so there is a helper script you need to run
-
-```
-mkdir coverage_artifacts
-python ../build-support/collect_coverage.py CMakeFiles/parquet.dir/src/ coverage_artifacts
-```
-
-For codecov.io (using the provided project token -- be sure to keep this
-private):
-
-```
-cd coverage_artifacts
-codecov --token $PARQUET_CPP_CODECOV_TOKEN --gcov-args '\-l' --root $PARQUET_ROOT
-```
-
-For coveralls, install `cpp_coveralls`:
-
-```
-pip install cpp_coveralls
-```
-
-And the coveralls upload script:
-
-```
-coveralls -t $PARQUET_CPP_COVERAGE_TOKEN --gcov-options '\-l' -r $PARQUET_ROOT --exclude $PARQUET_ROOT/thirdparty --exclude $PARQUET_ROOT/build --exclude $NATIVE_TOOLCHAIN --exclude $PARQUET_ROOT/src/parquet/thrift
-```
-
-Note that `gcov` throws off artifacts from the STL, so I excluded my toolchain
-root stored in `$NATIVE_TOOLCHAIN` to avoid a cluttered coverage report.
-
-[1]: https://github.com/apache/parquet-cpp/blob/master/docs/Windows.md
+Discussions continue to be help on the Parquet dev mailing list.
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index 5cc8354..0000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,68 +0,0 @@
-# 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.
-
-# Operating system (build VM template)
-os: Visual Studio 2015
-
-matrix:
-  fast_finish: true
-
-environment:
-  matrix:
-    - GENERATOR: NMake Makefiles
-      PYTHON: "3.5"
-      ARCH: "64"
-      CONFIGURATION: "Release"
-    - GENERATOR: Visual Studio 14 2015 Win64
-      PYTHON: "3.5"
-      ARCH: "64"
-      CONFIGURATION: "Debug"
-    - GENERATOR: Visual Studio 15 2017 Win64
-      PYTHON: "3.5"
-      ARCH: "64"
-      CONFIGURATION: "Release"
-      APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
-      BOOST_ROOT: C:\Libraries\boost_1_64_0
-    - GENERATOR: Visual Studio 14 2015 Win64
-      PYTHON: "3.5"
-      ARCH: "64"
-      CONFIGURATION: "Debug"
-      USE_STATIC_CRT: "ON"
-    - GENERATOR: Visual Studio 14 2015 Win64
-      PYTHON: "3.5"
-      ARCH: "64"
-      CONFIGURATION: "Release"
-      USE_STATIC_CRT: "ON"
-    - GENERATOR: Visual Studio 14 2015 Win64
-      PYTHON: "3.5"
-      ARCH: "64"
-      CONFIGURATION: "Toolchain"
-
-  MSVC_DEFAULT_OPTIONS: ON
-  BOOST_ROOT: C:\Libraries\boost_1_63_0
-  BOOST_LIBRARYDIR: C:\Libraries\boost_1_63_0\lib64-msvc-14.0
-  USE_CLCACHE: false
-
-init:
-  - set MINICONDA=C:\Miniconda35-x64
-  - set PATH=%MINICONDA%;%MINICONDA%/Scripts;%MINICONDA%/Library/bin;%PATH%
-
-build_script:
-  - call ci\msvc-build.bat
-
-# Disable test discovery
-test: off
diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt
deleted file mode 100644
index 9566aec..0000000
--- a/benchmarks/CMakeLists.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-# 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.
-
-SET(LINK_LIBS
-  ${ARROW_LINK_LIBS}
-  ${PARQUET_MIN_TEST_LIBS}
-  thriftstatic)
-
-if (PARQUET_BUILD_BENCHMARKS)
-  add_executable(decode_benchmark decode_benchmark.cc)
-
-  add_dependencies(decode_benchmark gtest)
-
-  # This uses private APIs
-  target_link_libraries(decode_benchmark
-    ${LINK_LIBS}
-    parquet_static)
-endif()
diff --git a/benchmarks/decode_benchmark.cc b/benchmarks/decode_benchmark.cc
deleted file mode 100644
index 3ae32b4..0000000
--- a/benchmarks/decode_benchmark.cc
+++ /dev/null
@@ -1,471 +0,0 @@
-// 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.
-
-#include <stdio.h>
-#include <iostream>
-#include <random>
-
-#include "arrow/test-util.h"
-#include "arrow/util/compression.h"
-#include "arrow/util/compression_snappy.h"
-
-#include "parquet/encoding-internal.h"
-#include "parquet/util/logging.h"
-#include "parquet/util/stopwatch.h"
-
-/**
- * Test bed for encodings and some utilities to measure their throughput.
- * TODO: this file needs some major cleanup.
- */
-
-class DeltaBitPackEncoder {
- public:
-  explicit DeltaBitPackEncoder(int mini_block_size = 8) {
-    mini_block_size_ = mini_block_size;
-  }
-
-  void Add(int64_t v) { values_.push_back(v); }
-
-  uint8_t* Encode(int* encoded_len) {
-    uint8_t* result = new uint8_t[10 * 1024 * 1024];
-    int num_mini_blocks = static_cast<int>(arrow::BitUtil::CeilDiv(num_values() - 1,
-                                                                   mini_block_size_));
-    uint8_t* mini_block_widths = NULL;
-
-    arrow::BitWriter writer(result, 10 * 1024 * 1024);
-
-    // Writer the size of each block. We only use 1 block currently.
-    writer.PutVlqInt(static_cast<uint32_t>(num_mini_blocks * mini_block_size_));
-
-    // Write the number of mini blocks.
-    writer.PutVlqInt(static_cast<uint32_t>(num_mini_blocks));
-
-    // Write the number of values.
-    writer.PutVlqInt(num_values() - 1);
-
-    // Write the first value.
-    writer.PutZigZagVlqInt(static_cast<uint32_t>(values_[0]));
-
-    // Compute the values as deltas and the min delta.
-    int64_t min_delta = std::numeric_limits<int64_t>::max();
-    for (size_t i = values_.size() - 1; i > 0; --i) {
-      values_[i] -= values_[i - 1];
-      min_delta = std::min(min_delta, values_[i]);
-    }
-
-    // Write out the min delta.
-    writer.PutZigZagVlqInt(static_cast<int32_t>(min_delta));
-
-    // We need to save num_mini_blocks bytes to store the bit widths of the mini
-    // blocks.
-    mini_block_widths = writer.GetNextBytePtr(num_mini_blocks);
-
-    int idx = 1;
-    for (int i = 0; i < num_mini_blocks; ++i) {
-      int n = std::min(mini_block_size_, num_values() - idx);
-
-      // Compute the max delta in this mini block.
-      int64_t max_delta = std::numeric_limits<int64_t>::min();
-      for (int j = 0; j < n; ++j) {
-        max_delta = std::max(values_[idx + j], max_delta);
-      }
-
-      // The bit width for this block is the number of bits needed to store
-      // (max_delta - min_delta).
-      int bit_width = arrow::BitUtil::NumRequiredBits(max_delta - min_delta);
-      mini_block_widths[i] = static_cast<uint8_t>(bit_width);
-
-      // Encode this mini blocking using min_delta and bit_width
-      for (int j = 0; j < n; ++j) {
-        writer.PutValue(values_[idx + j] - min_delta, bit_width);
-      }
-
-      // Pad out the last block.
-      for (int j = n; j < mini_block_size_; ++j) {
-        writer.PutValue(0, bit_width);
-      }
-      idx += n;
-    }
-
-    writer.Flush();
-    *encoded_len = writer.bytes_written();
-    return result;
-  }
-
-  int num_values() const { return static_cast<int>(values_.size()); }
-
- private:
-  int mini_block_size_;
-  std::vector<int64_t> values_;
-};
-
-class DeltaLengthByteArrayEncoder {
- public:
-  explicit DeltaLengthByteArrayEncoder(int mini_block_size = 8)
-      : len_encoder_(mini_block_size),
-        buffer_(new uint8_t[10 * 1024 * 1024]),
-        offset_(0),
-        plain_encoded_len_(0) {}
-
-  void Add(const std::string& s) {
-    Add(reinterpret_cast<const uint8_t*>(s.data()), static_cast<int>(s.size()));
-  }
-
-  void Add(const uint8_t* ptr, int len) {
-    plain_encoded_len_ += static_cast<int>(len + sizeof(int));
-    len_encoder_.Add(len);
-    memcpy(buffer_ + offset_, ptr, len);
-    offset_ += len;
-  }
-
-  uint8_t* Encode(int* encoded_len) {
-    uint8_t* encoded_lengths = len_encoder_.Encode(encoded_len);
-    memmove(buffer_ + *encoded_len + sizeof(int), buffer_, offset_);
-    memcpy(buffer_, encoded_len, sizeof(int));
-    memcpy(buffer_ + sizeof(int), encoded_lengths, *encoded_len);
-    *encoded_len += static_cast<int>(offset_ + sizeof(int));
-    return buffer_;
-  }
-
-  int num_values() const { return len_encoder_.num_values(); }
-  int plain_encoded_len() const { return plain_encoded_len_; }
-
- private:
-  DeltaBitPackEncoder len_encoder_;
-  uint8_t* buffer_;
-  int offset_;
-  int plain_encoded_len_;
-};
-
-class DeltaByteArrayEncoder {
- public:
-  DeltaByteArrayEncoder() : plain_encoded_len_(0) {}
-
-  void Add(const std::string& s) {
-    plain_encoded_len_ += static_cast<int>(s.size() + sizeof(int));
-    int min_len = static_cast<int>(std::min(s.size(), last_value_.size()));
-    int prefix_len = 0;
-    for (int i = 0; i < min_len; ++i) {
-      if (s[i] == last_value_[i]) {
-        ++prefix_len;
-      } else {
-        break;
-      }
-    }
-    prefix_len_encoder_.Add(prefix_len);
-    suffix_encoder_.Add(reinterpret_cast<const uint8_t*>(s.data()) + prefix_len,
-                        static_cast<int>(s.size() - prefix_len));
-    last_value_ = s;
-  }
-
-  uint8_t* Encode(int* encoded_len) {
-    int prefix_buffer_len;
-    uint8_t* prefix_buffer = prefix_len_encoder_.Encode(&prefix_buffer_len);
-    int suffix_buffer_len;
-    uint8_t* suffix_buffer = suffix_encoder_.Encode(&suffix_buffer_len);
-
-    uint8_t* buffer = new uint8_t[10 * 1024 * 1024];
-    memcpy(buffer, &prefix_buffer_len, sizeof(int));
-    memcpy(buffer + sizeof(int), prefix_buffer, prefix_buffer_len);
-    memcpy(buffer + sizeof(int) + prefix_buffer_len, suffix_buffer, suffix_buffer_len);
-    *encoded_len = static_cast<int>(sizeof(int) + prefix_buffer_len + suffix_buffer_len);
-    return buffer;
-  }
-
-  int num_values() const { return prefix_len_encoder_.num_values(); }
-  int plain_encoded_len() const { return plain_encoded_len_; }
-
- private:
-  DeltaBitPackEncoder prefix_len_encoder_;
-  DeltaLengthByteArrayEncoder suffix_encoder_;
-  std::string last_value_;
-  int plain_encoded_len_;
-};
-
-uint64_t TestPlainIntEncoding(const uint8_t* data, int num_values, int batch_size) {
-  uint64_t result = 0;
-  parquet::PlainDecoder<parquet::Int64Type> decoder(nullptr);
-  decoder.SetData(num_values, data, static_cast<int>(num_values * sizeof(int64_t)));
-  std::vector<int64_t> values(batch_size);
-  for (int i = 0; i < num_values;) {
-    int n = decoder.Decode(values.data(), batch_size);
-    for (int j = 0; j < n; ++j) {
-      result += values[j];
-    }
-    i += n;
-  }
-  return result;
-}
-
-uint64_t TestBinaryPackedEncoding(const char* name, const std::vector<int64_t>& values,
-                                  int benchmark_iters = -1,
-                                  int benchmark_batch_size = 1) {
-  int mini_block_size;
-  if (values.size() < 8) {
-    mini_block_size = 8;
-  } else if (values.size() < 16) {
-    mini_block_size = 16;
-  } else {
-    mini_block_size = 32;
-  }
-  parquet::DeltaBitPackDecoder<parquet::Int64Type> decoder(nullptr);
-  DeltaBitPackEncoder encoder(mini_block_size);
-  for (size_t i = 0; i < values.size(); ++i) {
-    encoder.Add(values[i]);
-  }
-
-  int raw_len = static_cast<int>(encoder.num_values() * sizeof(int));
-  int len;
-  uint8_t* buffer = encoder.Encode(&len);
-
-  if (benchmark_iters == -1) {
-    printf("%s\n", name);
-    printf("  Raw len: %d\n", raw_len);
-    printf("  Encoded len: %d (%0.2f%%)\n", len,
-           static_cast<float>(len) * 100.0f / static_cast<float>(raw_len));
-    decoder.SetData(encoder.num_values(), buffer, len);
-    for (int i = 0; i < encoder.num_values(); ++i) {
-      int64_t x = 0;
-      decoder.Decode(&x, 1);
-      if (values[i] != x) {
-        std::cerr << "Bad: " << i << std::endl;
-        std::cerr << "  " << x << " != " << values[i] << std::endl;
-        break;
-      }
-    }
-    return 0;
-  } else {
-    printf("%s\n", name);
-    printf("  Raw len: %d\n", raw_len);
-    printf("  Encoded len: %d (%0.2f%%)\n", len,
-           static_cast<float>(len) * 100.0f / static_cast<float>(raw_len));
-
-    uint64_t result = 0;
-    std::vector<int64_t> buf(benchmark_batch_size);
-    parquet::StopWatch sw;
-    sw.Start();
-    for (int k = 0; k < benchmark_iters; ++k) {
-      decoder.SetData(encoder.num_values(), buffer, len);
-      for (size_t i = 0; i < values.size();) {
-        int n = decoder.Decode(buf.data(), benchmark_batch_size);
-        for (int j = 0; j < n; ++j) {
-          result += buf[j];
-        }
-        i += n;
-      }
-    }
-    uint64_t elapsed = sw.Stop();
-    double num_ints = static_cast<double>(values.size() * benchmark_iters) * 1000.;
-    printf("%s rate (batch size = %2d): %0.3fM per second.\n", name, benchmark_batch_size,
-           num_ints / static_cast<double>(elapsed));
-    return result;
-  }
-}
-
-#define DECODE_TEST(NAME, FN, DATA, BATCH_SIZE)                                \
-  sw.Start();                                                                  \
-  for (int i = 0; i < NUM_ITERS; ++i) {                                        \
-    FN(reinterpret_cast<uint8_t*>(&DATA[0]), NUM_VALUES, BATCH_SIZE);          \
-  }                                                                            \
-  elapsed = sw.Stop();                                                         \
-  printf("%s rate (batch size = %2d): %0.3fM per second.\n", NAME, BATCH_SIZE, \
-         mult / static_cast<double>(elapsed));
-
-void TestPlainIntCompressed(::arrow::Codec* codec, const std::vector<int64_t>& data,
-                            int num_iters, int batch_size) {
-  const uint8_t* raw_data = reinterpret_cast<const uint8_t*>(&data[0]);
-  int uncompressed_len = static_cast<int>(data.size() * sizeof(int64_t));
-  uint8_t* decompressed_data = new uint8_t[uncompressed_len];
-
-  int64_t max_compressed_size = codec->MaxCompressedLen(uncompressed_len, raw_data);
-  uint8_t* compressed_data = new uint8_t[max_compressed_size];
-  int64_t compressed_len;
-  DCHECK(codec
-             ->Compress(uncompressed_len, raw_data, max_compressed_size, compressed_data,
-                        &compressed_len)
-             .ok());
-
-  printf("\n%s:\n  Uncompressed len: %d\n  Compressed len:   %d\n", codec->name(),
-         uncompressed_len, static_cast<int>(compressed_len));
-
-  double mult = static_cast<double>(num_iters * data.size()) * 1000.;
-  parquet::StopWatch sw;
-  sw.Start();
-  uint64_t r = 0;
-  for (int i = 0; i < num_iters; ++i) {
-    ABORT_NOT_OK(codec->Decompress(compressed_len, compressed_data, uncompressed_len,
-                                   decompressed_data));
-    r += TestPlainIntEncoding(decompressed_data, static_cast<int>(data.size()),
-                              batch_size);
-  }
-  int64_t elapsed = sw.Stop();
-  printf("Compressed(%s) plain int rate (batch size = %2d): %0.3fM per second.\n",
-         codec->name(), batch_size, mult / static_cast<double>(elapsed));
-
-  delete[] compressed_data;
-  delete[] decompressed_data;
-}
-
-void TestBinaryPacking() {
-  std::vector<int64_t> values;
-  values.clear();
-  for (int i = 0; i < 100; ++i) values.push_back(0);
-  TestBinaryPackedEncoding("Zeros", values);
-
-  values.clear();
-  for (int i = 1; i <= 5; ++i) values.push_back(i);
-  TestBinaryPackedEncoding("Example 1", values);
-
-  values.clear();
-  values.push_back(7);
-  values.push_back(5);
-  values.push_back(3);
-  values.push_back(1);
-  values.push_back(2);
-  values.push_back(3);
-  values.push_back(4);
-  values.push_back(5);
-  TestBinaryPackedEncoding("Example 2", values);
-
-  // Test rand ints between 0 and 10K
-  values.clear();
-  int seed = 0;
-  std::mt19937 gen(seed);
-  std::uniform_int_distribution<int> d(0, 10000);
-  for (int i = 0; i < 500000; ++i) {
-    values.push_back(d(gen));
-  }
-  TestBinaryPackedEncoding("Rand [0, 10000)", values);
-
-  // Test rand ints between 0 and 100
-  values.clear();
-  std::uniform_int_distribution<int> d1(0, 100);
-  for (int i = 0; i < 500000; ++i) {
-    values.push_back(d1(gen));
-  }
-  TestBinaryPackedEncoding("Rand [0, 100)", values);
-}
-
-void TestDeltaLengthByteArray() {
-  parquet::DeltaLengthByteArrayDecoder decoder(nullptr);
-  DeltaLengthByteArrayEncoder encoder;
-
-  std::vector<std::string> values;
-  values.push_back("Hello");
-  values.push_back("World");
-  values.push_back("Foobar");
-  values.push_back("ABCDEF");
-
-  for (size_t i = 0; i < values.size(); ++i) {
-    encoder.Add(values[i]);
-  }
-
-  int len = 0;
-  uint8_t* buffer = encoder.Encode(&len);
-  printf("DeltaLengthByteArray\n  Raw len: %d\n  Encoded len: %d\n",
-         encoder.plain_encoded_len(), len);
-  decoder.SetData(encoder.num_values(), buffer, len);
-  for (int i = 0; i < encoder.num_values(); ++i) {
-    parquet::ByteArray v = {0, NULL};
-    decoder.Decode(&v, 1);
-    std::string r = std::string(reinterpret_cast<const char*>(v.ptr), v.len);
-    if (r != values[i]) {
-      std::cout << "Bad " << r << " != " << values[i] << std::endl;
-    }
-  }
-}
-
-void TestDeltaByteArray() {
-  parquet::DeltaByteArrayDecoder decoder(nullptr);
-  DeltaByteArrayEncoder encoder;
-
-  std::vector<std::string> values;
-
-  // Wikipedia example
-  values.push_back("myxa");
-  values.push_back("myxophyta");
-  values.push_back("myxopod");
-  values.push_back("nab");
-  values.push_back("nabbed");
-  values.push_back("nabbing");
-  values.push_back("nabit");
-  values.push_back("nabk");
-  values.push_back("nabob");
-  values.push_back("nacarat");
-  values.push_back("nacelle");
-
-  for (size_t i = 0; i < values.size(); ++i) {
-    encoder.Add(values[i]);
-  }
-
-  int len = 0;
-  uint8_t* buffer = encoder.Encode(&len);
-  printf("DeltaLengthByteArray\n  Raw len: %d\n  Encoded len: %d\n",
-         encoder.plain_encoded_len(), len);
-  decoder.SetData(encoder.num_values(), buffer, len);
-  for (int i = 0; i < encoder.num_values(); ++i) {
-    parquet::ByteArray v;
-    decoder.Decode(&v, 1);
-    std::string r = std::string(reinterpret_cast<const char*>(v.ptr), v.len);
-    if (r != values[i]) {
-      std::cout << "Bad " << r << " != " << values[i] << std::endl;
-    }
-  }
-}
-
-int main(int argc, char** argv) {
-  TestBinaryPacking();
-  TestDeltaLengthByteArray();
-  TestDeltaByteArray();
-
-  parquet::StopWatch sw;
-  uint64_t elapsed = 0;
-
-  const int NUM_VALUES = 1024 * 1024;
-  const int NUM_ITERS = 10;
-  const double mult = NUM_VALUES * NUM_ITERS * 1000.;
-
-  std::vector<int64_t> plain_int_data;
-  plain_int_data.resize(NUM_VALUES);
-
-  DECODE_TEST("Plain decoder", TestPlainIntEncoding, plain_int_data, 1);
-  DECODE_TEST("Plain decoder", TestPlainIntEncoding, plain_int_data, 16);
-  DECODE_TEST("Plain decoder", TestPlainIntEncoding, plain_int_data, 32);
-  DECODE_TEST("Plain decoder", TestPlainIntEncoding, plain_int_data, 64);
-
-  // Test rand ints between 0 and 10K
-  std::vector<int64_t> values;
-  int seed = 0;
-  std::mt19937 gen(seed);
-  std::uniform_int_distribution<int> d(0, 10000);
-  for (int i = 0; i < 1000000; ++i) {
-    values.push_back(d(gen));
-  }
-  TestBinaryPackedEncoding("Rand 0-10K", values, 100, 1);
-  TestBinaryPackedEncoding("Rand 0-10K", values, 100, 16);
-  TestBinaryPackedEncoding("Rand 0-10K", values, 100, 32);
-  TestBinaryPackedEncoding("Rand 0-10K", values, 100, 64);
-
-  ::arrow::SnappyCodec snappy_codec;
-
-  TestPlainIntCompressed(&snappy_codec, values, 100, 1);
-  TestPlainIntCompressed(&snappy_codec, values, 100, 16);
-  TestPlainIntCompressed(&snappy_codec, values, 100, 32);
-  TestPlainIntCompressed(&snappy_codec, values, 100, 64);
-
-  return 0;
-}
diff --git a/build-support/clang_format_exclusions.txt b/build-support/clang_format_exclusions.txt
deleted file mode 100644
index ce72d2f..0000000
--- a/build-support/clang_format_exclusions.txt
+++ /dev/null
@@ -1 +0,0 @@
-*_generated*
diff --git a/build-support/collect_coverage.py b/build-support/collect_coverage.py
deleted file mode 100755
index 6712760..0000000
--- a/build-support/collect_coverage.py
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env python
-# 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.
-
-import os
-import os.path as osp
-import shutil
-import sys
-
-
-def is_coverage_file(path):
-    return path.endswith('gcno') or path.endswith('gcda')
-
-
-def copy_files(path, outpath='.'):
-    for root, dirs, files in os.walk(path):
-        for fname in files:
-            if not is_coverage_file(fname):
-                continue
-            relpath = osp.join(root, fname)
-            dstpath = '_'.join((root.replace(path, '').replace('/', '_'),
-                                fname))
-
-            shutil.copy(relpath, osp.join(outpath, dstpath))
-
-if __name__ == '__main__':
-    path = sys.argv[1]
-    outpath = sys.argv[2]
-    copy_files(path, outpath)
diff --git a/build-support/cpplint.py b/build-support/cpplint.py
deleted file mode 100755
index ece520b..0000000
--- a/build-support/cpplint.py
+++ /dev/null
@@ -1,6323 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (c) 2009 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#    * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#    * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#    * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Does google-lint on c++ files.
-
-The goal of this script is to identify places in the code that *may*
-be in non-compliance with google style.  It does not attempt to fix
-up these problems -- the point is to educate.  It does also not
-attempt to find all problems, or to ensure that everything it does
-find is legitimately a problem.
-
-In particular, we can get very confused by /* and // inside strings!
-We do a small hack, which is to ignore //'s with "'s after them on the
-same line, but it is far from perfect (in either direction).
-"""
-
-import codecs
-import copy
-import getopt
-import math  # for log
-import os
-import re
-import sre_compile
-import string
-import sys
-import unicodedata
-
-
-_USAGE = """
-Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
-                   [--counting=total|toplevel|detailed] [--root=subdir]
-                   [--linelength=digits]
-        <file> [file] ...
-
-  The style guidelines this tries to follow are those in
-    http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
-
-  Every problem is given a confidence score from 1-5, with 5 meaning we are
-  certain of the problem, and 1 meaning it could be a legitimate construct.
-  This will miss some errors, and is not a substitute for a code review.
-
-  To suppress false-positive errors of a certain category, add a
-  'NOLINT(category)' comment to the line.  NOLINT or NOLINT(*)
-  suppresses errors of all categories on that line.
-
-  The files passed in will be linted; at least one file must be provided.
-  Default linted extensions are .cc, .cpp, .cu, .cuh and .h.  Change the
-  extensions with the --extensions flag.
-
-  Flags:
-
-    output=vs7
-      By default, the output is formatted to ease emacs parsing.  Visual Studio
-      compatible output (vs7) may also be used.  Other formats are unsupported.
-
-    verbose=#
-      Specify a number 0-5 to restrict errors to certain verbosity levels.
-
-    filter=-x,+y,...
-      Specify a comma-separated list of category-filters to apply: only
-      error messages whose category names pass the filters will be printed.
-      (Category names are printed with the message and look like
-      "[whitespace/indent]".)  Filters are evaluated left to right.
-      "-FOO" and "FOO" means "do not print categories that start with FOO".
-      "+FOO" means "do print categories that start with FOO".
-
-      Examples: --filter=-whitespace,+whitespace/braces
-                --filter=whitespace,runtime/printf,+runtime/printf_format
-                --filter=-,+build/include_what_you_use
-
-      To see a list of all the categories used in cpplint, pass no arg:
-         --filter=
-
-    counting=total|toplevel|detailed
-      The total number of errors found is always printed. If
-      'toplevel' is provided, then the count of errors in each of
-      the top-level categories like 'build' and 'whitespace' will
-      also be printed. If 'detailed' is provided, then a count
-      is provided for each category like 'build/class'.
-
-    root=subdir
-      The root directory used for deriving header guard CPP variable.
-      By default, the header guard CPP variable is calculated as the relative
-      path to the directory that contains .git, .hg, or .svn.  When this flag
-      is specified, the relative path is calculated from the specified
-      directory. If the specified directory does not exist, this flag is
-      ignored.
-
-      Examples:
-        Assuming that src/.git exists, the header guard CPP variables for
-        src/chrome/browser/ui/browser.h are:
-
-        No flag => CHROME_BROWSER_UI_BROWSER_H_
-        --root=chrome => BROWSER_UI_BROWSER_H_
-        --root=chrome/browser => UI_BROWSER_H_
-
-    linelength=digits
-      This is the allowed line length for the project. The default value is
-      80 characters.
-
-      Examples:
-        --linelength=120
-
-    extensions=extension,extension,...
-      The allowed file extensions that cpplint will check
-
-      Examples:
-        --extensions=hpp,cpp
-
-    cpplint.py supports per-directory configurations specified in CPPLINT.cfg
-    files. CPPLINT.cfg file can contain a number of key=value pairs.
-    Currently the following options are supported:
-
-      set noparent
-      filter=+filter1,-filter2,...
-      exclude_files=regex
-      linelength=80
-
-    "set noparent" option prevents cpplint from traversing directory tree
-    upwards looking for more .cfg files in parent directories. This option
-    is usually placed in the top-level project directory.
-
-    The "filter" option is similar in function to --filter flag. It specifies
-    message filters in addition to the |_DEFAULT_FILTERS| and those specified
-    through --filter command-line flag.
-
-    "exclude_files" allows to specify a regular expression to be matched against
-    a file name. If the expression matches, the file is skipped and not run
-    through liner.
-
-    "linelength" allows to specify the allowed line length for the project.
-
-    CPPLINT.cfg has an effect on files in the same directory and all
-    sub-directories, unless overridden by a nested configuration file.
-
-      Example file:
-        filter=-build/include_order,+build/include_alpha
-        exclude_files=.*\.cc
-
-    The above example disables build/include_order warning and enables
-    build/include_alpha as well as excludes all .cc from being
-    processed by linter, in the current directory (where the .cfg
-    file is located) and all sub-directories.
-"""
-
-# We categorize each error message we print.  Here are the categories.
-# We want an explicit list so we can list them all in cpplint --filter=.
-# If you add a new error message with a new category, add it to the list
-# here!  cpplint_unittest.py should tell you if you forget to do this.
-_ERROR_CATEGORIES = [
-    'build/class',
-    'build/c++11',
-    'build/deprecated',
-    'build/endif_comment',
-    'build/explicit_make_pair',
-    'build/forward_decl',
-    'build/header_guard',
-    'build/include',
-    'build/include_alpha',
-    'build/include_order',
-    'build/include_what_you_use',
-    'build/namespaces',
-    'build/printf_format',
-    'build/storage_class',
-    'legal/copyright',
-    'readability/alt_tokens',
-    'readability/braces',
-    'readability/casting',
-    'readability/check',
-    'readability/constructors',
-    'readability/fn_size',
-    'readability/function',
-    'readability/inheritance',
-    'readability/multiline_comment',
-    'readability/multiline_string',
-    'readability/namespace',
-    'readability/nolint',
-    'readability/nul',
-    'readability/strings',
-    'readability/todo',
-    'readability/utf8',
-    'runtime/arrays',
-    'runtime/casting',
-    'runtime/explicit',
-    'runtime/int',
-    'runtime/init',
-    'runtime/invalid_increment',
-    'runtime/member_string_references',
-    'runtime/memset',
-    'runtime/indentation_namespace',
-    'runtime/operator',
-    'runtime/printf',
-    'runtime/printf_format',
-    'runtime/references',
-    'runtime/string',
-    'runtime/threadsafe_fn',
-    'runtime/vlog',
-    'whitespace/blank_line',
-    'whitespace/braces',
-    'whitespace/comma',
-    'whitespace/comments',
-    'whitespace/empty_conditional_body',
-    'whitespace/empty_loop_body',
-    'whitespace/end_of_line',
-    'whitespace/ending_newline',
-    'whitespace/forcolon',
-    'whitespace/indent',
-    'whitespace/line_length',
-    'whitespace/newline',
-    'whitespace/operators',
-    'whitespace/parens',
-    'whitespace/semicolon',
-    'whitespace/tab',
-    'whitespace/todo',
-    ]
-
-# These error categories are no longer enforced by cpplint, but for backwards-
-# compatibility they may still appear in NOLINT comments.
-_LEGACY_ERROR_CATEGORIES = [
-    'readability/streams',
-    ]
-
-# The default state of the category filter. This is overridden by the --filter=
-# flag. By default all errors are on, so only add here categories that should be
-# off by default (i.e., categories that must be enabled by the --filter= flags).
-# All entries here should start with a '-' or '+', as in the --filter= flag.
-_DEFAULT_FILTERS = ['-build/include_alpha']
-
-# We used to check for high-bit characters, but after much discussion we
-# decided those were OK, as long as they were in UTF-8 and didn't represent
-# hard-coded international strings, which belong in a separate i18n file.
-
-# C++ headers
-_CPP_HEADERS = frozenset([
-    # Legacy
-    'algobase.h',
-    'algo.h',
-    'alloc.h',
-    'builtinbuf.h',
-    'bvector.h',
-    'complex.h',
-    'defalloc.h',
-    'deque.h',
-    'editbuf.h',
-    'fstream.h',
-    'function.h',
-    'hash_map',
-    'hash_map.h',
-    'hash_set',
-    'hash_set.h',
-    'hashtable.h',
-    'heap.h',
-    'indstream.h',
-    'iomanip.h',
-    'iostream.h',
-    'istream.h',
-    'iterator.h',
-    'list.h',
-    'map.h',
-    'multimap.h',
-    'multiset.h',
-    'ostream.h',
-    'pair.h',
-    'parsestream.h',
-    'pfstream.h',
-    'procbuf.h',
-    'pthread_alloc',
-    'pthread_alloc.h',
-    'rope',
-    'rope.h',
-    'ropeimpl.h',
-    'set.h',
-    'slist',
-    'slist.h',
-    'stack.h',
-    'stdiostream.h',
-    'stl_alloc.h',
-    'stl_relops.h',
-    'streambuf.h',
-    'stream.h',
-    'strfile.h',
-    'strstream.h',
-    'tempbuf.h',
-    'tree.h',
-    'type_traits.h',
-    'vector.h',
-    # 17.6.1.2 C++ library headers
-    'algorithm',
-    'array',
-    'atomic',
-    'bitset',
-    'chrono',
-    'codecvt',
-    'complex',
-    'condition_variable',
-    'deque',
-    'exception',
-    'forward_list',
-    'fstream',
-    'functional',
-    'future',
-    'initializer_list',
-    'iomanip',
-    'ios',
-    'iosfwd',
-    'iostream',
-    'istream',
-    'iterator',
-    'limits',
-    'list',
-    'locale',
-    'map',
-    'memory',
-    'mutex',
-    'new',
-    'numeric',
-    'ostream',
-    'queue',
-    'random',
-    'ratio',
-    'regex',
-    'set',
-    'sstream',
-    'stack',
-    'stdexcept',
-    'streambuf',
-    'string',
-    'strstream',
-    'system_error',
-    'thread',
-    'tuple',
-    'typeindex',
-    'typeinfo',
-    'type_traits',
-    'unordered_map',
-    'unordered_set',
-    'utility',
-    'valarray',
-    'vector',
-    # 17.6.1.2 C++ headers for C library facilities
-    'cassert',
-    'ccomplex',
-    'cctype',
-    'cerrno',
-    'cfenv',
-    'cfloat',
-    'cinttypes',
-    'ciso646',
-    'climits',
-    'clocale',
-    'cmath',
-    'csetjmp',
-    'csignal',
-    'cstdalign',
-    'cstdarg',
-    'cstdbool',
-    'cstddef',
-    'cstdint',
-    'cstdio',
-    'cstdlib',
-    'cstring',
-    'ctgmath',
-    'ctime',
-    'cuchar',
-    'cwchar',
-    'cwctype',
-    ])
-
-
-# These headers are excluded from [build/include] and [build/include_order]
-# checks:
-# - Anything not following google file name conventions (containing an
-#   uppercase character, such as Python.h or nsStringAPI.h, for example).
-# - Lua headers.
-_THIRD_PARTY_HEADERS_PATTERN = re.compile(
-    r'^(?:[^/]*[A-Z][^/]*\.h|lua\.h|lauxlib\.h|lualib\.h)$')
-
-
-# Assertion macros.  These are defined in base/logging.h and
-# testing/base/gunit.h.  Note that the _M versions need to come first
-# for substring matching to work.
-_CHECK_MACROS = [
-    'DCHECK', 'CHECK',
-    'EXPECT_TRUE_M', 'EXPECT_TRUE',
-    'ASSERT_TRUE_M', 'ASSERT_TRUE',
-    'EXPECT_FALSE_M', 'EXPECT_FALSE',
-    'ASSERT_FALSE_M', 'ASSERT_FALSE',
-    ]
-
-# Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE
-_CHECK_REPLACEMENT = dict([(m, {}) for m in _CHECK_MACROS])
-
-for op, replacement in [('==', 'EQ'), ('!=', 'NE'),
-                        ('>=', 'GE'), ('>', 'GT'),
-                        ('<=', 'LE'), ('<', 'LT')]:
-  _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement
-  _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement
-  _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement
-  _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement
-  _CHECK_REPLACEMENT['EXPECT_TRUE_M'][op] = 'EXPECT_%s_M' % replacement
-  _CHECK_REPLACEMENT['ASSERT_TRUE_M'][op] = 'ASSERT_%s_M' % replacement
-
-for op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'),
-                            ('>=', 'LT'), ('>', 'LE'),
-                            ('<=', 'GT'), ('<', 'GE')]:
-  _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement
-  _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement
-  _CHECK_REPLACEMENT['EXPECT_FALSE_M'][op] = 'EXPECT_%s_M' % inv_replacement
-  _CHECK_REPLACEMENT['ASSERT_FALSE_M'][op] = 'ASSERT_%s_M' % inv_replacement
-
-# Alternative tokens and their replacements.  For full list, see section 2.5
-# Alternative tokens [lex.digraph] in the C++ standard.
-#
-# Digraphs (such as '%:') are not included here since it's a mess to
-# match those on a word boundary.
-_ALT_TOKEN_REPLACEMENT = {
-    'and': '&&',
-    'bitor': '|',
-    'or': '||',
-    'xor': '^',
-    'compl': '~',
-    'bitand': '&',
-    'and_eq': '&=',
-    'or_eq': '|=',
-    'xor_eq': '^=',
-    'not': '!',
-    'not_eq': '!='
-    }
-
-# Compile regular expression that matches all the above keywords.  The "[ =()]"
-# bit is meant to avoid matching these keywords outside of boolean expressions.
-#
-# False positives include C-style multi-line comments and multi-line strings
-# but those have always been troublesome for cpplint.
-_ALT_TOKEN_REPLACEMENT_PATTERN = re.compile(
-    r'[ =()](' + ('|'.join(_ALT_TOKEN_REPLACEMENT.keys())) + r')(?=[ (]|$)')
-
-
-# These constants define types of headers for use with
-# _IncludeState.CheckNextIncludeOrder().
-_C_SYS_HEADER = 1
-_CPP_SYS_HEADER = 2
-_LIKELY_MY_HEADER = 3
-_POSSIBLE_MY_HEADER = 4
-_OTHER_HEADER = 5
-
-# These constants define the current inline assembly state
-_NO_ASM = 0       # Outside of inline assembly block
-_INSIDE_ASM = 1   # Inside inline assembly block
-_END_ASM = 2      # Last line of inline assembly block
-_BLOCK_ASM = 3    # The whole block is an inline assembly block
-
-# Match start of assembly blocks
-_MATCH_ASM = re.compile(r'^\s*(?:asm|_asm|__asm|__asm__)'
-                        r'(?:\s+(volatile|__volatile__))?'
-                        r'\s*[{(]')
-
-
-_regexp_compile_cache = {}
-
-# {str, set(int)}: a map from error categories to sets of linenumbers
-# on which those errors are expected and should be suppressed.
-_error_suppressions = {}
-
-# The root directory used for deriving header guard CPP variable.
-# This is set by --root flag.
-_root = None
-
-# The allowed line length of files.
-# This is set by --linelength flag.
-_line_length = 80
-
-# The allowed extensions for file names
-# This is set by --extensions flag.
-_valid_extensions = set(['cc', 'h', 'cpp', 'cu', 'cuh'])
-
-def ParseNolintSuppressions(filename, raw_line, linenum, error):
-  """Updates the global list of error-suppressions.
-
-  Parses any NOLINT comments on the current line, updating the global
-  error_suppressions store.  Reports an error if the NOLINT comment
-  was malformed.
-
-  Args:
-    filename: str, the name of the input file.
-    raw_line: str, the line of input text, with comments.
-    linenum: int, the number of the current line.
-    error: function, an error handler.
-  """
-  matched = Search(r'\bNOLINT(NEXTLINE)?\b(\([^)]+\))?', raw_line)
-  if matched:
-    if matched.group(1):
-      suppressed_line = linenum + 1
-    else:
-      suppressed_line = linenum
-    category = matched.group(2)
-    if category in (None, '(*)'):  # => "suppress all"
-      _error_suppressions.setdefault(None, set()).add(suppressed_line)
-    else:
-      if category.startswith('(') and category.endswith(')'):
-        category = category[1:-1]
-        if category in _ERROR_CATEGORIES:
-          _error_suppressions.setdefault(category, set()).add(suppressed_line)
-        elif category not in _LEGACY_ERROR_CATEGORIES:
-          error(filename, linenum, 'readability/nolint', 5,
-                'Unknown NOLINT error category: %s' % category)
-
-
-def ResetNolintSuppressions():
-  """Resets the set of NOLINT suppressions to empty."""
-  _error_suppressions.clear()
-
-
-def IsErrorSuppressedByNolint(category, linenum):
-  """Returns true if the specified error category is suppressed on this line.
-
-  Consults the global error_suppressions map populated by
-  ParseNolintSuppressions/ResetNolintSuppressions.
-
-  Args:
-    category: str, the category of the error.
-    linenum: int, the current line number.
-  Returns:
-    bool, True iff the error should be suppressed due to a NOLINT comment.
-  """
-  return (linenum in _error_suppressions.get(category, set()) or
-          linenum in _error_suppressions.get(None, set()))
-
-
-def Match(pattern, s):
-  """Matches the string with the pattern, caching the compiled regexp."""
-  # The regexp compilation caching is inlined in both Match and Search for
-  # performance reasons; factoring it out into a separate function turns out
-  # to be noticeably expensive.
-  if pattern not in _regexp_compile_cache:
-    _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
-  return _regexp_compile_cache[pattern].match(s)
-
-
-def ReplaceAll(pattern, rep, s):
-  """Replaces instances of pattern in a string with a replacement.
-
-  The compiled regex is kept in a cache shared by Match and Search.
-
-  Args:
-    pattern: regex pattern
-    rep: replacement text
-    s: search string
-
-  Returns:
-    string with replacements made (or original string if no replacements)
-  """
-  if pattern not in _regexp_compile_cache:
-    _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
-  return _regexp_compile_cache[pattern].sub(rep, s)
-
-
-def Search(pattern, s):
-  """Searches the string for the pattern, caching the compiled regexp."""
-  if pattern not in _regexp_compile_cache:
-    _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
-  return _regexp_compile_cache[pattern].search(s)
-
-
-class _IncludeState(object):
-  """Tracks line numbers for includes, and the order in which includes appear.
-
-  include_list contains list of lists of (header, line number) pairs.
-  It's a lists of lists rather than just one flat list to make it
-  easier to update across preprocessor boundaries.
-
-  Call CheckNextIncludeOrder() once for each header in the file, passing
-  in the type constants defined above. Calls in an illegal order will
-  raise an _IncludeError with an appropriate error message.
-
-  """
-  # self._section will move monotonically through this set. If it ever
-  # needs to move backwards, CheckNextIncludeOrder will raise an error.
-  _INITIAL_SECTION = 0
-  _MY_H_SECTION = 1
-  _C_SECTION = 2
-  _CPP_SECTION = 3
-  _OTHER_H_SECTION = 4
-
-  _TYPE_NAMES = {
-      _C_SYS_HEADER: 'C system header',
-      _CPP_SYS_HEADER: 'C++ system header',
-      _LIKELY_MY_HEADER: 'header this file implements',
-      _POSSIBLE_MY_HEADER: 'header this file may implement',
-      _OTHER_HEADER: 'other header',
-      }
-  _SECTION_NAMES = {
-      _INITIAL_SECTION: "... nothing. (This can't be an error.)",
-      _MY_H_SECTION: 'a header this file implements',
-      _C_SECTION: 'C system header',
-      _CPP_SECTION: 'C++ system header',
-      _OTHER_H_SECTION: 'other header',
-      }
-
-  def __init__(self):
-    self.include_list = [[]]
-    self.ResetSection('')
-
-  def FindHeader(self, header):
-    """Check if a header has already been included.
-
-    Args:
-      header: header to check.
-    Returns:
-      Line number of previous occurrence, or -1 if the header has not
-      been seen before.
-    """
-    for section_list in self.include_list:
-      for f in section_list:
-        if f[0] == header:
-          return f[1]
-    return -1
-
-  def ResetSection(self, directive):
-    """Reset section checking for preprocessor directive.
-
-    Args:
-      directive: preprocessor directive (e.g. "if", "else").
-    """
-    # The name of the current section.
-    self._section = self._INITIAL_SECTION
-    # The path of last found header.
-    self._last_header = ''
-
-    # Update list of includes.  Note that we never pop from the
-    # include list.
-    if directive in ('if', 'ifdef', 'ifndef'):
-      self.include_list.append([])
-    elif directive in ('else', 'elif'):
-      self.include_list[-1] = []
-
-  def SetLastHeader(self, header_path):
-    self._last_header = header_path
-
-  def CanonicalizeAlphabeticalOrder(self, header_path):
-    """Returns a path canonicalized for alphabetical comparison.
-
-    - replaces "-" with "_" so they both cmp the same.
-    - removes '-inl' since we don't require them to be after the main header.
-    - lowercase everything, just in case.
-
-    Args:
-      header_path: Path to be canonicalized.
-
-    Returns:
-      Canonicalized path.
-    """
-    return header_path.replace('-inl.h', '.h').replace('-', '_').lower()
-
-  def IsInAlphabeticalOrder(self, clean_lines, linenum, header_path):
-    """Check if a header is in alphabetical order with the previous header.
-
-    Args:
-      clean_lines: A CleansedLines instance containing the file.
-      linenum: The number of the line to check.
-      header_path: Canonicalized header to be checked.
-
-    Returns:
-      Returns true if the header is in alphabetical order.
-    """
-    # If previous section is different from current section, _last_header will
-    # be reset to empty string, so it's always less than current header.
-    #
-    # If previous line was a blank line, assume that the headers are
-    # intentionally sorted the way they are.
-    if (self._last_header > header_path and
-        Match(r'^\s*#\s*include\b', clean_lines.elided[linenum - 1])):
-      return False
-    return True
-
-  def CheckNextIncludeOrder(self, header_type):
-    """Returns a non-empty error message if the next header is out of order.
-
-    This function also updates the internal state to be ready to check
-    the next include.
-
-    Args:
-      header_type: One of the _XXX_HEADER constants defined above.
-
-    Returns:
-      The empty string if the header is in the right order, or an
-      error message describing what's wrong.
-
-    """
-    error_message = ('Found %s after %s' %
-                     (self._TYPE_NAMES[header_type],
-                      self._SECTION_NAMES[self._section]))
-
-    last_section = self._section
-
-    if header_type == _C_SYS_HEADER:
-      if self._section <= self._C_SECTION:
-        self._section = self._C_SECTION
-      else:
-        self._last_header = ''
-        return error_message
-    elif header_type == _CPP_SYS_HEADER:
-      if self._section <= self._CPP_SECTION:
-        self._section = self._CPP_SECTION
-      else:
-        self._last_header = ''
-        return error_message
-    elif header_type == _LIKELY_MY_HEADER:
-      if self._section <= self._MY_H_SECTION:
-        self._section = self._MY_H_SECTION
-      else:
-        self._section = self._OTHER_H_SECTION
-    elif header_type == _POSSIBLE_MY_HEADER:
-      if self._section <= self._MY_H_SECTION:
-        self._section = self._MY_H_SECTION
-      else:
-        # This will always be the fallback because we're not sure
-        # enough that the header is associated with this file.
-        self._section = self._OTHER_H_SECTION
-    else:
-      assert header_type == _OTHER_HEADER
-      self._section = self._OTHER_H_SECTION
-
-    if last_section != self._section:
-      self._last_header = ''
-
-    return ''
-
-
-class _CppLintState(object):
-  """Maintains module-wide state.."""
-
-  def __init__(self):
-    self.verbose_level = 1  # global setting.
-    self.error_count = 0    # global count of reported errors
-    # filters to apply when emitting error messages
-    self.filters = _DEFAULT_FILTERS[:]
-    # backup of filter list. Used to restore the state after each file.
-    self._filters_backup = self.filters[:]
-    self.counting = 'total'  # In what way are we counting errors?
-    self.errors_by_category = {}  # string to int dict storing error counts
-
-    # output format:
-    # "emacs" - format that emacs can parse (default)
-    # "vs7" - format that Microsoft Visual Studio 7 can parse
-    self.output_format = 'emacs'
-
-  def SetOutputFormat(self, output_format):
-    """Sets the output format for errors."""
-    self.output_format = output_format
-
-  def SetVerboseLevel(self, level):
-    """Sets the module's verbosity, and returns the previous setting."""
-    last_verbose_level = self.verbose_level
-    self.verbose_level = level
-    return last_verbose_level
-
-  def SetCountingStyle(self, counting_style):
-    """Sets the module's counting options."""
-    self.counting = counting_style
-
-  def SetFilters(self, filters):
-    """Sets the error-message filters.
-
-    These filters are applied when deciding whether to emit a given
-    error message.
-
-    Args:
-      filters: A string of comma-separated filters (eg "+whitespace/indent").
-               Each filter should start with + or -; else we die.
-
-    Raises:
-      ValueError: The comma-separated filters did not all start with '+' or '-'.
-                  E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter"
-    """
-    # Default filters always have less priority than the flag ones.
-    self.filters = _DEFAULT_FILTERS[:]
-    self.AddFilters(filters)
-
-  def AddFilters(self, filters):
-    """ Adds more filters to the existing list of error-message filters. """
-    for filt in filters.split(','):
-      clean_filt = filt.strip()
-      if clean_filt:
-        self.filters.append(clean_filt)
-    for filt in self.filters:
-      if not (filt.startswith('+') or filt.startswith('-')):
-        raise ValueError('Every filter in --filters must start with + or -'
-                         ' (%s does not)' % filt)
-
-  def BackupFilters(self):
-    """ Saves the current filter list to backup storage."""
-    self._filters_backup = self.filters[:]
-
-  def RestoreFilters(self):
-    """ Restores filters previously backed up."""
-    self.filters = self._filters_backup[:]
-
-  def ResetErrorCounts(self):
-    """Sets the module's error statistic back to zero."""
-    self.error_count = 0
-    self.errors_by_category = {}
-
-  def IncrementErrorCount(self, category):
-    """Bumps the module's error statistic."""
-    self.error_count += 1
-    if self.counting in ('toplevel', 'detailed'):
-      if self.counting != 'detailed':
-        category = category.split('/')[0]
-      if category not in self.errors_by_category:
-        self.errors_by_category[category] = 0
-      self.errors_by_category[category] += 1
-
-  def PrintErrorCounts(self):
-    """Print a summary of errors by category, and the total."""
-    for category, count in self.errors_by_category.iteritems():
-      sys.stderr.write('Category \'%s\' errors found: %d\n' %
-                       (category, count))
-    sys.stderr.write('Total errors found: %d\n' % self.error_count)
-
-_cpplint_state = _CppLintState()
-
-
-def _OutputFormat():
-  """Gets the module's output format."""
-  return _cpplint_state.output_format
-
-
-def _SetOutputFormat(output_format):
-  """Sets the module's output format."""
-  _cpplint_state.SetOutputFormat(output_format)
-
-
-def _VerboseLevel():
-  """Returns the module's verbosity setting."""
-  return _cpplint_state.verbose_level
-
-
-def _SetVerboseLevel(level):
-  """Sets the module's verbosity, and returns the previous setting."""
-  return _cpplint_state.SetVerboseLevel(level)
-
-
-def _SetCountingStyle(level):
-  """Sets the module's counting options."""
-  _cpplint_state.SetCountingStyle(level)
-
-
-def _Filters():
-  """Returns the module's list of output filters, as a list."""
-  return _cpplint_state.filters
-
-
-def _SetFilters(filters):
-  """Sets the module's error-message filters.
-
-  These filters are applied when deciding whether to emit a given
-  error message.
-
-  Args:
-    filters: A string of comma-separated filters (eg "whitespace/indent").
-             Each filter should start with + or -; else we die.
-  """
-  _cpplint_state.SetFilters(filters)
-
-def _AddFilters(filters):
-  """Adds more filter overrides.
-
-  Unlike _SetFilters, this function does not reset the current list of filters
-  available.
-
-  Args:
-    filters: A string of comma-separated filters (eg "whitespace/indent").
-             Each filter should start with + or -; else we die.
-  """
-  _cpplint_state.AddFilters(filters)
-
-def _BackupFilters():
-  """ Saves the current filter list to backup storage."""
-  _cpplint_state.BackupFilters()
-
-def _RestoreFilters():
-  """ Restores filters previously backed up."""
-  _cpplint_state.RestoreFilters()
-
-class _FunctionState(object):
-  """Tracks current function name and the number of lines in its body."""
-
-  _NORMAL_TRIGGER = 250  # for --v=0, 500 for --v=1, etc.
-  _TEST_TRIGGER = 400    # about 50% more than _NORMAL_TRIGGER.
-
-  def __init__(self):
-    self.in_a_function = False
-    self.lines_in_function = 0
-    self.current_function = ''
-
-  def Begin(self, function_name):
-    """Start analyzing function body.
-
-    Args:
-      function_name: The name of the function being tracked.
-    """
-    self.in_a_function = True
-    self.lines_in_function = 0
-    self.current_function = function_name
-
-  def Count(self):
-    """Count line in current function body."""
-    if self.in_a_function:
-      self.lines_in_function += 1
-
-  def Check(self, error, filename, linenum):
-    """Report if too many lines in function body.
-
-    Args:
-      error: The function to call with any errors found.
-      filename: The name of the current file.
-      linenum: The number of the line to check.
-    """
-    if Match(r'T(EST|est)', self.current_function):
-      base_trigger = self._TEST_TRIGGER
-    else:
-      base_trigger = self._NORMAL_TRIGGER
-    trigger = base_trigger * 2**_VerboseLevel()
-
-    if self.lines_in_function > trigger:
-      error_level = int(math.log(self.lines_in_function / base_trigger, 2))
-      # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ...
-      if error_level > 5:
-        error_level = 5
-      error(filename, linenum, 'readability/fn_size', error_level,
-            'Small and focused functions are preferred:'
-            ' %s has %d non-comment lines'
-            ' (error triggered by exceeding %d lines).'  % (
-                self.current_function, self.lines_in_function, trigger))
-
-  def End(self):
-    """Stop analyzing function body."""
-    self.in_a_function = False
-
-
-class _IncludeError(Exception):
-  """Indicates a problem with the include order in a file."""
-  pass
-
-
-class FileInfo(object):
-  """Provides utility functions for filenames.
-
-  FileInfo provides easy access to the components of a file's path
-  relative to the project root.
-  """
-
-  def __init__(self, filename):
-    self._filename = filename
-
-  def FullName(self):
-    """Make Windows paths like Unix."""
-    return os.path.abspath(self._filename).replace('\\', '/')
-
-  def RepositoryName(self):
-    """FullName after removing the local path to the repository.
-
-    If we have a real absolute path name here we can try to do something smart:
-    detecting the root of the checkout and truncating /path/to/checkout from
-    the name so that we get header guards that don't include things like
-    "C:\Documents and Settings\..." or "/home/username/..." in them and thus
-    people on different computers who have checked the source out to different
-    locations won't see bogus errors.
-    """
-    fullname = self.FullName()
-
-    if os.path.exists(fullname):
-      project_dir = os.path.dirname(fullname)
-
-      if os.path.exists(os.path.join(project_dir, ".svn")):
-        # If there's a .svn file in the current directory, we recursively look
-        # up the directory tree for the top of the SVN checkout
-        root_dir = project_dir
-        one_up_dir = os.path.dirname(root_dir)
-        while os.path.exists(os.path.join(one_up_dir, ".svn")):
-          root_dir = os.path.dirname(root_dir)
-          one_up_dir = os.path.dirname(one_up_dir)
-
-        prefix = os.path.commonprefix([root_dir, project_dir])
-        return fullname[len(prefix) + 1:]
-
-      # Not SVN <= 1.6? Try to find a git, hg, or svn top level directory by
-      # searching up from the current path.
-      root_dir = os.path.dirname(fullname)
-      while (root_dir != os.path.dirname(root_dir) and
-             not os.path.exists(os.path.join(root_dir, ".git")) and
-             not os.path.exists(os.path.join(root_dir, ".hg")) and
-             not os.path.exists(os.path.join(root_dir, ".svn"))):
-        root_dir = os.path.dirname(root_dir)
-
-      if (os.path.exists(os.path.join(root_dir, ".git")) or
-          os.path.exists(os.path.join(root_dir, ".hg")) or
-          os.path.exists(os.path.join(root_dir, ".svn"))):
-        prefix = os.path.commonprefix([root_dir, project_dir])
-        return fullname[len(prefix) + 1:]
-
-    # Don't know what to do; header guard warnings may be wrong...
-    return fullname
-
-  def Split(self):
-    """Splits the file into the directory, basename, and extension.
-
-    For 'chrome/browser/browser.cc', Split() would
-    return ('chrome/browser', 'browser', '.cc')
-
-    Returns:
-      A tuple of (directory, basename, extension).
-    """
-
-    googlename = self.RepositoryName()
-    project, rest = os.path.split(googlename)
-    return (project,) + os.path.splitext(rest)
-
-  def BaseName(self):
-    """File base name - text after the final slash, before the final period."""
-    return self.Split()[1]
-
-  def Extension(self):
-    """File extension - text following the final period."""
-    return self.Split()[2]
-
-  def NoExtension(self):
-    """File has no source file extension."""
-    return '/'.join(self.Split()[0:2])
-
-  def IsSource(self):
-    """File has a source file extension."""
-    return self.Extension()[1:] in ('c', 'cc', 'cpp', 'cxx')
-
-
-def _ShouldPrintError(category, confidence, linenum):
-  """If confidence >= verbose, category passes filter and is not suppressed."""
-
-  # There are three ways we might decide not to print an error message:
-  # a "NOLINT(category)" comment appears in the source,
-  # the verbosity level isn't high enough, or the filters filter it out.
-  if IsErrorSuppressedByNolint(category, linenum):
-    return False
-
-  if confidence < _cpplint_state.verbose_level:
-    return False
-
-  is_filtered = False
-  for one_filter in _Filters():
-    if one_filter.startswith('-'):
-      if category.startswith(one_filter[1:]):
-        is_filtered = True
-    elif one_filter.startswith('+'):
-      if category.startswith(one_filter[1:]):
-        is_filtered = False
-    else:
-      assert False  # should have been checked for in SetFilter.
-  if is_filtered:
-    return False
-
-  return True
-
-
-def Error(filename, linenum, category, confidence, message):
-  """Logs the fact we've found a lint error.
-
-  We log where the error was found, and also our confidence in the error,
-  that is, how certain we are this is a legitimate style regression, and
-  not a misidentification or a use that's sometimes justified.
-
-  False positives can be suppressed by the use of
-  "cpplint(category)"  comments on the offending line.  These are
-  parsed into _error_suppressions.
-
-  Args:
-    filename: The name of the file containing the error.
-    linenum: The number of the line containing the error.
-    category: A string used to describe the "category" this bug
-      falls under: "whitespace", say, or "runtime".  Categories
-      may have a hierarchy separated by slashes: "whitespace/indent".
-    confidence: A number from 1-5 representing a confidence score for
-      the error, with 5 meaning that we are certain of the problem,
-      and 1 meaning that it could be a legitimate construct.
-    message: The error message.
-  """
-  if _ShouldPrintError(category, confidence, linenum):
-    _cpplint_state.IncrementErrorCount(category)
-    if _cpplint_state.output_format == 'vs7':
-      sys.stderr.write('%s(%s):  %s  [%s] [%d]\n' % (
-          filename, linenum, message, category, confidence))
-    elif _cpplint_state.output_format == 'eclipse':
-      sys.stderr.write('%s:%s: warning: %s  [%s] [%d]\n' % (
-          filename, linenum, message, category, confidence))
-    else:
-      sys.stderr.write('%s:%s:  %s  [%s] [%d]\n' % (
-          filename, linenum, message, category, confidence))
-
-
-# Matches standard C++ escape sequences per 2.13.2.3 of the C++ standard.
-_RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile(
-    r'\\([abfnrtv?"\\\']|\d+|x[0-9a-fA-F]+)')
-# Match a single C style comment on the same line.
-_RE_PATTERN_C_COMMENTS = r'/\*(?:[^*]|\*(?!/))*\*/'
-# Matches multi-line C style comments.
-# This RE is a little bit more complicated than one might expect, because we
-# have to take care of space removals tools so we can handle comments inside
-# statements better.
-# The current rule is: We only clear spaces from both sides when we're at the
-# end of the line. Otherwise, we try to remove spaces from the right side,
-# if this doesn't work we try on left side but only if there's a non-character
-# on the right.
-_RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile(
-    r'(\s*' + _RE_PATTERN_C_COMMENTS + r'\s*$|' +
-    _RE_PATTERN_C_COMMENTS + r'\s+|' +
-    r'\s+' + _RE_PATTERN_C_COMMENTS + r'(?=\W)|' +
-    _RE_PATTERN_C_COMMENTS + r')')
-
-
-def IsCppString(line):
-  """Does line terminate so, that the next symbol is in string constant.
-
-  This function does not consider single-line nor multi-line comments.
-
-  Args:
-    line: is a partial line of code starting from the 0..n.
-
-  Returns:
-    True, if next character appended to 'line' is inside a
-    string constant.
-  """
-
-  line = line.replace(r'\\', 'XX')  # after this, \\" does not match to \"
-  return ((line.count('"') - line.count(r'\"') - line.count("'\"'")) & 1) == 1
-
-
-def CleanseRawStrings(raw_lines):
-  """Removes C++11 raw strings from lines.
-
-    Before:
-      static const char kData[] = R"(
-          multi-line string
-          )";
-
-    After:
-      static const char kData[] = ""
-          (replaced by blank line)
-          "";
-
-  Args:
-    raw_lines: list of raw lines.
-
-  Returns:
-    list of lines with C++11 raw strings replaced by empty strings.
-  """
-
-  delimiter = None
-  lines_without_raw_strings = []
-  for line in raw_lines:
-    if delimiter:
-      # Inside a raw string, look for the end
-      end = line.find(delimiter)
-      if end >= 0:
-        # Found the end of the string, match leading space for this
-        # line and resume copying the original lines, and also insert
-        # a "" on the last line.
-        leading_space = Match(r'^(\s*)\S', line)
-        line = leading_space.group(1) + '""' + line[end + len(delimiter):]
-        delimiter = None
-      else:
-        # Haven't found the end yet, append a blank line.
-        line = '""'
-
-    # Look for beginning of a raw string, and replace them with
-    # empty strings.  This is done in a loop to handle multiple raw
-    # strings on the same line.
-    while delimiter is None:
-      # Look for beginning of a raw string.
-      # See 2.14.15 [lex.string] for syntax.
-      matched = Match(r'^(.*)\b(?:R|u8R|uR|UR|LR)"([^\s\\()]*)\((.*)$', line)
-      if matched:
-        delimiter = ')' + matched.group(2) + '"'
-
-        end = matched.group(3).find(delimiter)
-        if end >= 0:
-          # Raw string ended on same line
-          line = (matched.group(1) + '""' +
-                  matched.group(3)[end + len(delimiter):])
-          delimiter = None
-        else:
-          # Start of a multi-line raw string
-          line = matched.group(1) + '""'
-      else:
-        break
-
-    lines_without_raw_strings.append(line)
-
-  # TODO(unknown): if delimiter is not None here, we might want to
-  # emit a warning for unterminated string.
-  return lines_without_raw_strings
-
-
-def FindNextMultiLineCommentStart(lines, lineix):
-  """Find the beginning marker for a multiline comment."""
-  while lineix < len(lines):
-    if lines[lineix].strip().startswith('/*'):
-      # Only return this marker if the comment goes beyond this line
-      if lines[lineix].strip().find('*/', 2) < 0:
-        return lineix
-    lineix += 1
-  return len(lines)
-
-
-def FindNextMultiLineCommentEnd(lines, lineix):
-  """We are inside a comment, find the end marker."""
-  while lineix < len(lines):
-    if lines[lineix].strip().endswith('*/'):
-      return lineix
-    lineix += 1
-  return len(lines)
-
-
-def RemoveMultiLineCommentsFromRange(lines, begin, end):
-  """Clears a range of lines for multi-line comments."""
-  # Having // dummy comments makes the lines non-empty, so we will not get
-  # unnecessary blank line warnings later in the code.
-  for i in range(begin, end):
-    lines[i] = '/**/'
-
-
-def RemoveMultiLineComments(filename, lines, error):
-  """Removes multiline (c-style) comments from lines."""
-  lineix = 0
-  while lineix < len(lines):
-    lineix_begin = FindNextMultiLineCommentStart(lines, lineix)
-    if lineix_begin >= len(lines):
-      return
-    lineix_end = FindNextMultiLineCommentEnd(lines, lineix_begin)
-    if lineix_end >= len(lines):
-      error(filename, lineix_begin + 1, 'readability/multiline_comment', 5,
-            'Could not find end of multi-line comment')
-      return
-    RemoveMultiLineCommentsFromRange(lines, lineix_begin, lineix_end + 1)
-    lineix = lineix_end + 1
-
-
-def CleanseComments(line):
-  """Removes //-comments and single-line C-style /* */ comments.
-
-  Args:
-    line: A line of C++ source.
-
-  Returns:
-    The line with single-line comments removed.
-  """
-  commentpos = line.find('//')
-  if commentpos != -1 and not IsCppString(line[:commentpos]):
-    line = line[:commentpos].rstrip()
-  # get rid of /* ... */
-  return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line)
-
-
-class CleansedLines(object):
-  """Holds 4 copies of all lines with different preprocessing applied to them.
-
-  1) elided member contains lines without strings and comments.
-  2) lines member contains lines without comments.
-  3) raw_lines member contains all the lines without processing.
-  4) lines_without_raw_strings member is same as raw_lines, but with C++11 raw
-     strings removed.
-  All these members are of <type 'list'>, and of the same length.
-  """
-
-  def __init__(self, lines):
-    self.elided = []
-    self.lines = []
-    self.raw_lines = lines
-    self.num_lines = len(lines)
-    self.lines_without_raw_strings = CleanseRawStrings(lines)
-    for linenum in range(len(self.lines_without_raw_strings)):
-      self.lines.append(CleanseComments(
-          self.lines_without_raw_strings[linenum]))
-      elided = self._CollapseStrings(self.lines_without_raw_strings[linenum])
-      self.elided.append(CleanseComments(elided))
-
-  def NumLines(self):
-    """Returns the number of lines represented."""
-    return self.num_lines
-
-  @staticmethod
-  def _CollapseStrings(elided):
-    """Collapses strings and chars on a line to simple "" or '' blocks.
-
-    We nix strings first so we're not fooled by text like '"http://"'
-
-    Args:
-      elided: The line being processed.
-
-    Returns:
-      The line with collapsed strings.
-    """
-    if _RE_PATTERN_INCLUDE.match(elided):
-      return elided
-
-    # Remove escaped characters first to make quote/single quote collapsing
-    # basic.  Things that look like escaped characters shouldn't occur
-    # outside of strings and chars.
-    elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub('', elided)
-
-    # Replace quoted strings and digit separators.  Both single quotes
-    # and double quotes are processed in the same loop, otherwise
-    # nested quotes wouldn't work.
-    collapsed = ''
-    while True:
-      # Find the first quote character
-      match = Match(r'^([^\'"]*)([\'"])(.*)$', elided)
-      if not match:
-        collapsed += elided
-        break
-      head, quote, tail = match.groups()
-
-      if quote == '"':
-        # Collapse double quoted strings
-        second_quote = tail.find('"')
-        if second_quote >= 0:
-          collapsed += head + '""'
-          elided = tail[second_quote + 1:]
-        else:
-          # Unmatched double quote, don't bother processing the rest
-          # of the line since this is probably a multiline string.
-          collapsed += elided
-          break
-      else:
-        # Found single quote, check nearby text to eliminate digit separators.
-        #
-        # There is no special handling for floating point here, because
-        # the integer/fractional/exponent parts would all be parsed
-        # correctly as long as there are digits on both sides of the
-        # separator.  So we are fine as long as we don't see something
-        # like "0.'3" (gcc 4.9.0 will not allow this literal).
-        if Search(r'\b(?:0[bBxX]?|[1-9])[0-9a-fA-F]*$', head):
-          match_literal = Match(r'^((?:\'?[0-9a-zA-Z_])*)(.*)$', "'" + tail)
-          collapsed += head + match_literal.group(1).replace("'", '')
-          elided = match_literal.group(2)
-        else:
-          second_quote = tail.find('\'')
-          if second_quote >= 0:
-            collapsed += head + "''"
-            elided = tail[second_quote + 1:]
-          else:
-            # Unmatched single quote
-            collapsed += elided
-            break
-
-    return collapsed
-
-
-def FindEndOfExpressionInLine(line, startpos, stack):
-  """Find the position just after the end of current parenthesized expression.
-
-  Args:
-    line: a CleansedLines line.
-    startpos: start searching at this position.
-    stack: nesting stack at startpos.
-
-  Returns:
-    On finding matching end: (index just after matching end, None)
-    On finding an unclosed expression: (-1, None)
-    Otherwise: (-1, new stack at end of this line)
-  """
-  for i in xrange(startpos, len(line)):
-    char = line[i]
-    if char in '([{':
-      # Found start of parenthesized expression, push to expression stack
-      stack.append(char)
-    elif char == '<':
-      # Found potential start of template argument list
-      if i > 0 and line[i - 1] == '<':
-        # Left shift operator
-        if stack and stack[-1] == '<':
-          stack.pop()
-          if not stack:
-            return (-1, None)
-      elif i > 0 and Search(r'\boperator\s*$', line[0:i]):
-        # operator<, don't add to stack
-        continue
-      else:
-        # Tentative start of template argument list
-        stack.append('<')
-    elif char in ')]}':
-      # Found end of parenthesized expression.
-      #
-      # If we are currently expecting a matching '>', the pending '<'
-      # must have been an operator.  Remove them from expression stack.
-      while stack and stack[-1] == '<':
-        stack.pop()
-      if not stack:
-        return (-1, None)
-      if ((stack[-1] == '(' and char == ')') or
-          (stack[-1] == '[' and char == ']') or
-          (stack[-1] == '{' and char == '}')):
-        stack.pop()
-        if not stack:
-          return (i + 1, None)
-      else:
-        # Mismatched parentheses
-        return (-1, None)
-    elif char == '>':
-      # Found potential end of template argument list.
-
-      # Ignore "->" and operator functions
-      if (i > 0 and
-          (line[i - 1] == '-' or Search(r'\boperator\s*$', line[0:i - 1]))):
-        continue
-
-      # Pop the stack if there is a matching '<'.  Otherwise, ignore
-      # this '>' since it must be an operator.
-      if stack:
-        if stack[-1] == '<':
-          stack.pop()
-          if not stack:
-            return (i + 1, None)
-    elif char == ';':
-      # Found something that look like end of statements.  If we are currently
-      # expecting a '>', the matching '<' must have been an operator, since
-      # template argument list should not contain statements.
-      while stack and stack[-1] == '<':
-        stack.pop()
-      if not stack:
-        return (-1, None)
-
-  # Did not find end of expression or unbalanced parentheses on this line
-  return (-1, stack)
-
-
-def CloseExpression(clean_lines, linenum, pos):
-  """If input points to ( or { or [ or <, finds the position that closes it.
-
-  If lines[linenum][pos] points to a '(' or '{' or '[' or '<', finds the
-  linenum/pos that correspond to the closing of the expression.
-
-  TODO(unknown): cpplint spends a fair bit of time matching parentheses.
-  Ideally we would want to index all opening and closing parentheses once
-  and have CloseExpression be just a simple lookup, but due to preprocessor
-  tricks, this is not so easy.
-
-  Args:
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    pos: A position on the line.
-
-  Returns:
-    A tuple (line, linenum, pos) pointer *past* the closing brace, or
-    (line, len(lines), -1) if we never find a close.  Note we ignore
-    strings and comments when matching; and the line we return is the
-    'cleansed' line at linenum.
-  """
-
-  line = clean_lines.elided[linenum]
-  if (line[pos] not in '({[<') or Match(r'<[<=]', line[pos:]):
-    return (line, clean_lines.NumLines(), -1)
-
-  # Check first line
-  (end_pos, stack) = FindEndOfExpressionInLine(line, pos, [])
-  if end_pos > -1:
-    return (line, linenum, end_pos)
-
-  # Continue scanning forward
-  while stack and linenum < clean_lines.NumLines() - 1:
-    linenum += 1
-    line = clean_lines.elided[linenum]
-    (end_pos, stack) = FindEndOfExpressionInLine(line, 0, stack)
-    if end_pos > -1:
-      return (line, linenum, end_pos)
-
-  # Did not find end of expression before end of file, give up
-  return (line, clean_lines.NumLines(), -1)
-
-
-def FindStartOfExpressionInLine(line, endpos, stack):
-  """Find position at the matching start of current expression.
-
-  This is almost the reverse of FindEndOfExpressionInLine, but note
-  that the input position and returned position differs by 1.
-
-  Args:
-    line: a CleansedLines line.
-    endpos: start searching at this position.
-    stack: nesting stack at endpos.
-
-  Returns:
-    On finding matching start: (index at matching start, None)
-    On finding an unclosed expression: (-1, None)
-    Otherwise: (-1, new stack at beginning of this line)
-  """
-  i = endpos
-  while i >= 0:
-    char = line[i]
-    if char in ')]}':
-      # Found end of expression, push to expression stack
-      stack.append(char)
-    elif char == '>':
-      # Found potential end of template argument list.
-      #
-      # Ignore it if it's a "->" or ">=" or "operator>"
-      if (i > 0 and
-          (line[i - 1] == '-' or
-           Match(r'\s>=\s', line[i - 1:]) or
-           Search(r'\boperator\s*$', line[0:i]))):
-        i -= 1
-      else:
-        stack.append('>')
-    elif char == '<':
-      # Found potential start of template argument list
-      if i > 0 and line[i - 1] == '<':
-        # Left shift operator
-        i -= 1
-      else:
-        # If there is a matching '>', we can pop the expression stack.
-        # Otherwise, ignore this '<' since it must be an operator.
-        if stack and stack[-1] == '>':
-          stack.pop()
-          if not stack:
-            return (i, None)
-    elif char in '([{':
-      # Found start of expression.
-      #
-      # If there are any unmatched '>' on the stack, they must be
-      # operators.  Remove those.
-      while stack and stack[-1] == '>':
-        stack.pop()
-      if not stack:
-        return (-1, None)
-      if ((char == '(' and stack[-1] == ')') or
-          (char == '[' and stack[-1] == ']') or
-          (char == '{' and stack[-1] == '}')):
-        stack.pop()
-        if not stack:
-          return (i, None)
-      else:
-        # Mismatched parentheses
-        return (-1, None)
-    elif char == ';':
-      # Found something that look like end of statements.  If we are currently
-      # expecting a '<', the matching '>' must have been an operator, since
-      # template argument list should not contain statements.
-      while stack and stack[-1] == '>':
-        stack.pop()
-      if not stack:
-        return (-1, None)
-
-    i -= 1
-
-  return (-1, stack)
-
-
-def ReverseCloseExpression(clean_lines, linenum, pos):
-  """If input points to ) or } or ] or >, finds the position that opens it.
-
-  If lines[linenum][pos] points to a ')' or '}' or ']' or '>', finds the
-  linenum/pos that correspond to the opening of the expression.
-
-  Args:
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    pos: A position on the line.
-
-  Returns:
-    A tuple (line, linenum, pos) pointer *at* the opening brace, or
-    (line, 0, -1) if we never find the matching opening brace.  Note
-    we ignore strings and comments when matching; and the line we
-    return is the 'cleansed' line at linenum.
-  """
-  line = clean_lines.elided[linenum]
-  if line[pos] not in ')}]>':
-    return (line, 0, -1)
-
-  # Check last line
-  (start_pos, stack) = FindStartOfExpressionInLine(line, pos, [])
-  if start_pos > -1:
-    return (line, linenum, start_pos)
-
-  # Continue scanning backward
-  while stack and linenum > 0:
-    linenum -= 1
-    line = clean_lines.elided[linenum]
-    (start_pos, stack) = FindStartOfExpressionInLine(line, len(line) - 1, stack)
-    if start_pos > -1:
-      return (line, linenum, start_pos)
-
-  # Did not find start of expression before beginning of file, give up
-  return (line, 0, -1)
-
-
-def CheckForCopyright(filename, lines, error):
-  """Logs an error if no Copyright message appears at the top of the file."""
-
-  # We'll say it should occur by line 10. Don't forget there's a
-  # dummy line at the front.
-  for line in xrange(1, min(len(lines), 11)):
-    if re.search(r'Copyright', lines[line], re.I): break
-  else:                       # means no copyright line was found
-    error(filename, 0, 'legal/copyright', 5,
-          'No copyright message found.  '
-          'You should have a line: "Copyright [year] <Copyright Owner>"')
-
-
-def GetIndentLevel(line):
-  """Return the number of leading spaces in line.
-
-  Args:
-    line: A string to check.
-
-  Returns:
-    An integer count of leading spaces, possibly zero.
-  """
-  indent = Match(r'^( *)\S', line)
-  if indent:
-    return len(indent.group(1))
-  else:
-    return 0
-
-
-def GetHeaderGuardCPPVariable(filename):
-  """Returns the CPP variable that should be used as a header guard.
-
-  Args:
-    filename: The name of a C++ header file.
-
-  Returns:
-    The CPP variable that should be used as a header guard in the
-    named file.
-
-  """
-
-  # Restores original filename in case that cpplint is invoked from Emacs's
-  # flymake.
-  filename = re.sub(r'_flymake\.h$', '.h', filename)
-  filename = re.sub(r'/\.flymake/([^/]*)$', r'/\1', filename)
-  # Replace 'c++' with 'cpp'.
-  filename = filename.replace('C++', 'cpp').replace('c++', 'cpp')
-
-  fileinfo = FileInfo(filename)
-  file_path_from_root = fileinfo.RepositoryName()
-  if _root:
-    file_path_from_root = re.sub('^' + _root + os.sep, '', file_path_from_root)
-  return re.sub(r'[^a-zA-Z0-9]', '_', file_path_from_root).upper() + '_'
-
-
-def CheckForHeaderGuard(filename, clean_lines, error):
-  """Checks that the file contains a header guard.
-
-  Logs an error if no #ifndef header guard is present.  For other
-  headers, checks that the full pathname is used.
-
-  Args:
-    filename: The name of the C++ header file.
-    clean_lines: A CleansedLines instance containing the file.
-    error: The function to call with any errors found.
-  """
-
-  # Don't check for header guards if there are error suppression
-  # comments somewhere in this file.
-  #
-  # Because this is silencing a warning for a nonexistent line, we
-  # only support the very specific NOLINT(build/header_guard) syntax,
-  # and not the general NOLINT or NOLINT(*) syntax.
-  raw_lines = clean_lines.lines_without_raw_strings
-  for i in raw_lines:
-    if Search(r'//\s*NOLINT\(build/header_guard\)', i):
-      return
-
-  cppvar = GetHeaderGuardCPPVariable(filename)
-
-  ifndef = ''
-  ifndef_linenum = 0
-  define = ''
-  endif = ''
-  endif_linenum = 0
-  for linenum, line in enumerate(raw_lines):
-    linesplit = line.split()
-    if len(linesplit) >= 2:
-      # find the first occurrence of #ifndef and #define, save arg
-      if not ifndef and linesplit[0] == '#ifndef':
-        # set ifndef to the header guard presented on the #ifndef line.
-        ifndef = linesplit[1]
-        ifndef_linenum = linenum
-      if not define and linesplit[0] == '#define':
-        define = linesplit[1]
-    # find the last occurrence of #endif, save entire line
-    if line.startswith('#endif'):
-      endif = line
-      endif_linenum = linenum
-
-  if not ifndef or not define or ifndef != define:
-    error(filename, 0, 'build/header_guard', 5,
-          'No #ifndef header guard found, suggested CPP variable is: %s' %
-          cppvar)
-    return
-
-  # The guard should be PATH_FILE_H_, but we also allow PATH_FILE_H__
-  # for backward compatibility.
-  if ifndef != cppvar:
-    error_level = 0
-    if ifndef != cppvar + '_':
-      error_level = 5
-
-    ParseNolintSuppressions(filename, raw_lines[ifndef_linenum], ifndef_linenum,
-                            error)
-    error(filename, ifndef_linenum, 'build/header_guard', error_level,
-          '#ifndef header guard has wrong style, please use: %s' % cppvar)
-
-  # Check for "//" comments on endif line.
-  ParseNolintSuppressions(filename, raw_lines[endif_linenum], endif_linenum,
-                          error)
-  match = Match(r'#endif\s*//\s*' + cppvar + r'(_)?\b', endif)
-  if match:
-    if match.group(1) == '_':
-      # Issue low severity warning for deprecated double trailing underscore
-      error(filename, endif_linenum, 'build/header_guard', 0,
-            '#endif line should be "#endif  // %s"' % cppvar)
-    return
-
-  # Didn't find the corresponding "//" comment.  If this file does not
-  # contain any "//" comments at all, it could be that the compiler
-  # only wants "/**/" comments, look for those instead.
-  no_single_line_comments = True
-  for i in xrange(1, len(raw_lines) - 1):
-    line = raw_lines[i]
-    if Match(r'^(?:(?:\'(?:\.|[^\'])*\')|(?:"(?:\.|[^"])*")|[^\'"])*//', line):
-      no_single_line_comments = False
-      break
-
-  if no_single_line_comments:
-    match = Match(r'#endif\s*/\*\s*' + cppvar + r'(_)?\s*\*/', endif)
-    if match:
-      if match.group(1) == '_':
-        # Low severity warning for double trailing underscore
-        error(filename, endif_linenum, 'build/header_guard', 0,
-              '#endif line should be "#endif  /* %s */"' % cppvar)
-      return
-
-  # Didn't find anything
-  error(filename, endif_linenum, 'build/header_guard', 5,
-        '#endif line should be "#endif  // %s"' % cppvar)
-
-
-def CheckHeaderFileIncluded(filename, include_state, error):
-  """Logs an error if a .cc file does not include its header."""
-
-  # Do not check test files
-  if filename.endswith('_test.cc') or filename.endswith('_unittest.cc'):
-    return
-
-  fileinfo = FileInfo(filename)
-  headerfile = filename[0:len(filename) - 2] + 'h'
-  if not os.path.exists(headerfile):
-    return
-  headername = FileInfo(headerfile).RepositoryName()
-  first_include = 0
-  for section_list in include_state.include_list:
-    for f in section_list:
-      if headername in f[0] or f[0] in headername:
-        return
-      if not first_include:
-        first_include = f[1]
-
-  error(filename, first_include, 'build/include', 5,
-        '%s should include its header file %s' % (fileinfo.RepositoryName(),
-                                                  headername))
-
-
-def CheckForBadCharacters(filename, lines, error):
-  """Logs an error for each line containing bad characters.
-
-  Two kinds of bad characters:
-
-  1. Unicode replacement characters: These indicate that either the file
-  contained invalid UTF-8 (likely) or Unicode replacement characters (which
-  it shouldn't).  Note that it's possible for this to throw off line
-  numbering if the invalid UTF-8 occurred adjacent to a newline.
-
-  2. NUL bytes.  These are problematic for some tools.
-
-  Args:
-    filename: The name of the current file.
-    lines: An array of strings, each representing a line of the file.
-    error: The function to call with any errors found.
-  """
-  for linenum, line in enumerate(lines):
-    if u'\ufffd' in line:
-      error(filename, linenum, 'readability/utf8', 5,
-            'Line contains invalid UTF-8 (or Unicode replacement character).')
-    if '\0' in line:
-      error(filename, linenum, 'readability/nul', 5, 'Line contains NUL byte.')
-
-
-def CheckForNewlineAtEOF(filename, lines, error):
-  """Logs an error if there is no newline char at the end of the file.
-
-  Args:
-    filename: The name of the current file.
-    lines: An array of strings, each representing a line of the file.
-    error: The function to call with any errors found.
-  """
-
-  # The array lines() was created by adding two newlines to the
-  # original file (go figure), then splitting on \n.
-  # To verify that the file ends in \n, we just have to make sure the
-  # last-but-two element of lines() exists and is empty.
-  if len(lines) < 3 or lines[-2]:
-    error(filename, len(lines) - 2, 'whitespace/ending_newline', 5,
-          'Could not find a newline character at the end of the file.')
-
-
-def CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error):
-  """Logs an error if we see /* ... */ or "..." that extend past one line.
-
-  /* ... */ comments are legit inside macros, for one line.
-  Otherwise, we prefer // comments, so it's ok to warn about the
-  other.  Likewise, it's ok for strings to extend across multiple
-  lines, as long as a line continuation character (backslash)
-  terminates each line. Although not currently prohibited by the C++
-  style guide, it's ugly and unnecessary. We don't do well with either
-  in this lint program, so we warn about both.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    error: The function to call with any errors found.
-  """
-  line = clean_lines.elided[linenum]
-
-  # Remove all \\ (escaped backslashes) from the line. They are OK, and the
-  # second (escaped) slash may trigger later \" detection erroneously.
-  line = line.replace('\\\\', '')
-
-  if line.count('/*') > line.count('*/'):
-    error(filename, linenum, 'readability/multiline_comment', 5,
-          'Complex multi-line /*...*/-style comment found. '
-          'Lint may give bogus warnings.  '
-          'Consider replacing these with //-style comments, '
-          'with #if 0...#endif, '
-          'or with more clearly structured multi-line comments.')
-
-  if (line.count('"') - line.count('\\"')) % 2:
-    error(filename, linenum, 'readability/multiline_string', 5,
-          'Multi-line string ("...") found.  This lint script doesn\'t '
-          'do well with such strings, and may give bogus warnings.  '
-          'Use C++11 raw strings or concatenation instead.')
-
-
-# (non-threadsafe name, thread-safe alternative, validation pattern)
-#
-# The validation pattern is used to eliminate false positives such as:
-#  _rand();               // false positive due to substring match.
-#  ->rand();              // some member function rand().
-#  ACMRandom rand(seed);  // some variable named rand.
-#  ISAACRandom rand();    // another variable named rand.
-#
-# Basically we require the return value of these functions to be used
-# in some expression context on the same line by matching on some
-# operator before the function name.  This eliminates constructors and
-# member function calls.
-_UNSAFE_FUNC_PREFIX = r'(?:[-+*/=%^&|(<]\s*|>\s+)'
-_THREADING_LIST = (
-    ('asctime(', 'asctime_r(', _UNSAFE_FUNC_PREFIX + r'asctime\([^)]+\)'),
-    ('ctime(', 'ctime_r(', _UNSAFE_FUNC_PREFIX + r'ctime\([^)]+\)'),
-    ('getgrgid(', 'getgrgid_r(', _UNSAFE_FUNC_PREFIX + r'getgrgid\([^)]+\)'),
-    ('getgrnam(', 'getgrnam_r(', _UNSAFE_FUNC_PREFIX + r'getgrnam\([^)]+\)'),
-    ('getlogin(', 'getlogin_r(', _UNSAFE_FUNC_PREFIX + r'getlogin\(\)'),
-    ('getpwnam(', 'getpwnam_r(', _UNSAFE_FUNC_PREFIX + r'getpwnam\([^)]+\)'),
-    ('getpwuid(', 'getpwuid_r(', _UNSAFE_FUNC_PREFIX + r'getpwuid\([^)]+\)'),
-    ('gmtime(', 'gmtime_r(', _UNSAFE_FUNC_PREFIX + r'gmtime\([^)]+\)'),
-    ('localtime(', 'localtime_r(', _UNSAFE_FUNC_PREFIX + r'localtime\([^)]+\)'),
-    ('rand(', 'rand_r(', _UNSAFE_FUNC_PREFIX + r'rand\(\)'),
-    ('strtok(', 'strtok_r(',
-     _UNSAFE_FUNC_PREFIX + r'strtok\([^)]+\)'),
-    ('ttyname(', 'ttyname_r(', _UNSAFE_FUNC_PREFIX + r'ttyname\([^)]+\)'),
-    )
-
-
-def CheckPosixThreading(filename, clean_lines, linenum, error):
-  """Checks for calls to thread-unsafe functions.
-
-  Much code has been originally written without consideration of
-  multi-threading. Also, engineers are relying on their old experience;
-  they have learned posix before threading extensions were added. These
-  tests guide the engineers to use thread-safe functions (when using
-  posix directly).
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    error: The function to call with any errors found.
-  """
-  line = clean_lines.elided[linenum]
-  for single_thread_func, multithread_safe_func, pattern in _THREADING_LIST:
-    # Additional pattern matching check to confirm that this is the
-    # function we are looking for
-    if Search(pattern, line):
-      error(filename, linenum, 'runtime/threadsafe_fn', 2,
-            'Consider using ' + multithread_safe_func +
-            '...) instead of ' + single_thread_func +
-            '...) for improved thread safety.')
-
-
-def CheckVlogArguments(filename, clean_lines, linenum, error):
-  """Checks that VLOG() is only used for defining a logging level.
-
-  For example, VLOG(2) is correct. VLOG(INFO), VLOG(WARNING), VLOG(ERROR), and
-  VLOG(FATAL) are not.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    error: The function to call with any errors found.
-  """
-  line = clean_lines.elided[linenum]
-  if Search(r'\bVLOG\((INFO|ERROR|WARNING|DFATAL|FATAL)\)', line):
-    error(filename, linenum, 'runtime/vlog', 5,
-          'VLOG() should be used with numeric verbosity level.  '
-          'Use LOG() if you want symbolic severity levels.')
-
-# Matches invalid increment: *count++, which moves pointer instead of
-# incrementing a value.
-_RE_PATTERN_INVALID_INCREMENT = re.compile(
-    r'^\s*\*\w+(\+\+|--);')
-
-
-def CheckInvalidIncrement(filename, clean_lines, linenum, error):
-  """Checks for invalid increment *count++.
-
-  For example following function:
-  void increment_counter(int* count) {
-    *count++;
-  }
-  is invalid, because it effectively does count++, moving pointer, and should
-  be replaced with ++*count, (*count)++ or *count += 1.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    error: The function to call with any errors found.
-  """
-  line = clean_lines.elided[linenum]
-  if _RE_PATTERN_INVALID_INCREMENT.match(line):
-    error(filename, linenum, 'runtime/invalid_increment', 5,
-          'Changing pointer instead of value (or unused value of operator*).')
-
-
-def IsMacroDefinition(clean_lines, linenum):
-  if Search(r'^#define', clean_lines[linenum]):
-    return True
-
-  if linenum > 0 and Search(r'\\$', clean_lines[linenum - 1]):
-    return True
-
-  return False
-
-
-def IsForwardClassDeclaration(clean_lines, linenum):
-  return Match(r'^\s*(\btemplate\b)*.*class\s+\w+;\s*$', clean_lines[linenum])
-
-
-class _BlockInfo(object):
-  """Stores information about a generic block of code."""
-
-  def __init__(self, seen_open_brace):
-    self.seen_open_brace = seen_open_brace
-    self.open_parentheses = 0
-    self.inline_asm = _NO_ASM
-    self.check_namespace_indentation = False
-
-  def CheckBegin(self, filename, clean_lines, linenum, error):
-    """Run checks that applies to text up to the opening brace.
-
-    This is mostly for checking the text after the class identifier
-    and the "{", usually where the base class is specified.  For other
-    blocks, there isn't much to check, so we always pass.
-
-    Args:
-      filename: The name of the current file.
-      clean_lines: A CleansedLines instance containing the file.
-      linenum: The number of the line to check.
-      error: The function to call with any errors found.
-    """
-    pass
-
-  def CheckEnd(self, filename, clean_lines, linenum, error):
-    """Run checks that applies to text after the closing brace.
-
-    This is mostly used for checking end of namespace comments.
-
-    Args:
-      filename: The name of the current file.
-      clean_lines: A CleansedLines instance containing the file.
-      linenum: The number of the line to check.
-      error: The function to call with any errors found.
-    """
-    pass
-
-  def IsBlockInfo(self):
-    """Returns true if this block is a _BlockInfo.
-
-    This is convenient for verifying that an object is an instance of
-    a _BlockInfo, but not an instance of any of the derived classes.
-
-    Returns:
-      True for this class, False for derived classes.
-    """
-    return self.__class__ == _BlockInfo
-
-
-class _ExternCInfo(_BlockInfo):
-  """Stores information about an 'extern "C"' block."""
-
-  def __init__(self):
-    _BlockInfo.__init__(self, True)
-
-
-class _ClassInfo(_BlockInfo):
-  """Stores information about a class."""
-
-  def __init__(self, name, class_or_struct, clean_lines, linenum):
-    _BlockInfo.__init__(self, False)
-    self.name = name
-    self.starting_linenum = linenum
-    self.is_derived = False
-    self.check_namespace_indentation = True
-    if class_or_struct == 'struct':
-      self.access = 'public'
-      self.is_struct = True
-    else:
-      self.access = 'private'
-      self.is_struct = False
-
-    # Remember initial indentation level for this class.  Using raw_lines here
-    # instead of elided to account for leading comments.
-    self.class_indent = GetIndentLevel(clean_lines.raw_lines[linenum])
-
-    # Try to find the end of the class.  This will be confused by things like:
-    #   class A {
-    #   } *x = { ...
-    #
-    # But it's still good enough for CheckSectionSpacing.
-    self.last_line = 0
-    depth = 0
-    for i in range(linenum, clean_lines.NumLines()):
-      line = clean_lines.elided[i]
-      depth += line.count('{') - line.count('}')
-      if not depth:
-        self.last_line = i
-        break
-
-  def CheckBegin(self, filename, clean_lines, linenum, error):
-    # Look for a bare ':'
-    if Search('(^|[^:]):($|[^:])', clean_lines.elided[linenum]):
-      self.is_derived = True
-
-  def CheckEnd(self, filename, clean_lines, linenum, error):
-    # If there is a DISALLOW macro, it should appear near the end of
-    # the class.
-    seen_last_thing_in_class = False
-    for i in xrange(linenum - 1, self.starting_linenum, -1):
-      match = Search(
-          r'\b(DISALLOW_COPY_AND_ASSIGN|DISALLOW_IMPLICIT_CONSTRUCTORS)\(' +
-          self.name + r'\)',
-          clean_lines.elided[i])
-      if match:
-        if seen_last_thing_in_class:
-          error(filename, i, 'readability/constructors', 3,
-                match.group(1) + ' should be the last thing in the class')
-        break
-
-      if not Match(r'^\s*$', clean_lines.elided[i]):
-        seen_last_thing_in_class = True
-
-    # Check that closing brace is aligned with beginning of the class.
-    # Only do this if the closing brace is indented by only whitespaces.
-    # This means we will not check single-line class definitions.
-    indent = Match(r'^( *)\}', clean_lines.elided[linenum])
-    if indent and len(indent.group(1)) != self.class_indent:
-      if self.is_struct:
-        parent = 'struct ' + self.name
-      else:
-        parent = 'class ' + self.name
-      error(filename, linenum, 'whitespace/indent', 3,
-            'Closing brace should be aligned with beginning of %s' % parent)
-
-
-class _NamespaceInfo(_BlockInfo):
-  """Stores information about a namespace."""
-
-  def __init__(self, name, linenum):
-    _BlockInfo.__init__(self, False)
-    self.name = name or ''
-    self.starting_linenum = linenum
-    self.check_namespace_indentation = True
-
-  def CheckEnd(self, filename, clean_lines, linenum, error):
-    """Check end of namespace comments."""
-    line = clean_lines.raw_lines[linenum]
-
-    # Check how many lines is enclosed in this namespace.  Don't issue
-    # warning for missing namespace comments if there aren't enough
-    # lines.  However, do apply checks if there is already an end of
-    # namespace comment and it's incorrect.
-    #
-    # TODO(unknown): We always want to check end of namespace comments
-    # if a namespace is large, but sometimes we also want to apply the
-    # check if a short namespace contained nontrivial things (something
-    # other than forward declarations).  There is currently no logic on
-    # deciding what these nontrivial things are, so this check is
-    # triggered by namespace size only, which works most of the time.
-    if (linenum - self.starting_linenum < 10
-        and not Match(r'};*\s*(//|/\*).*\bnamespace\b', line)):
-      return
-
-    # Look for matching comment at end of namespace.
-    #
-    # Note that we accept C style "/* */" comments for terminating
-    # namespaces, so that code that terminate namespaces inside
-    # preprocessor macros can be cpplint clean.
-    #
-    # We also accept stuff like "// end of namespace <name>." with the
-    # period at the end.
-    #
-    # Besides these, we don't accept anything else, otherwise we might
-    # get false negatives when existing comment is a substring of the
-    # expected namespace.
-    if self.name:
-      # Named namespace
-      if not Match((r'};*\s*(//|/\*).*\bnamespace\s+' + re.escape(self.name) +
-                    r'[\*/\.\\\s]*$'),
-                   line):
-        error(filename, linenum, 'readability/namespace', 5,
-              'Namespace should be terminated with "// namespace %s"' %
-              self.name)
-    else:
-      # Anonymous namespace
-      if not Match(r'};*\s*(//|/\*).*\bnamespace[\*/\.\\\s]*$', line):
-        # If "// namespace anonymous" or "// anonymous namespace (more text)",
-        # mention "// anonymous namespace" as an acceptable form
-        if Match(r'}.*\b(namespace anonymous|anonymous namespace)\b', line):
-          error(filename, linenum, 'readability/namespace', 5,
-                'Anonymous namespace should be terminated with "// namespace"'
-                ' or "// anonymous namespace"')
-        else:
-          error(filename, linenum, 'readability/namespace', 5,
-                'Anonymous namespace should be terminated with "// namespace"')
-
-
-class _PreprocessorInfo(object):
-  """Stores checkpoints of nesting stacks when #if/#else is seen."""
-
-  def __init__(self, stack_before_if):
-    # The entire nesting stack before #if
-    self.stack_before_if = stack_before_if
-
-    # The entire nesting stack up to #else
-    self.stack_before_else = []
-
-    # Whether we have already seen #else or #elif
-    self.seen_else = False
-
-
-class NestingState(object):
-  """Holds states related to parsing braces."""
-
-  def __init__(self):
-    # Stack for tracking all braces.  An object is pushed whenever we
-    # see a "{", and popped when we see a "}".  Only 3 types of
-    # objects are possible:
-    # - _ClassInfo: a class or struct.
-    # - _NamespaceInfo: a namespace.
-    # - _BlockInfo: some other type of block.
-    self.stack = []
-
-    # Top of the previous stack before each Update().
-    #
-    # Because the nesting_stack is updated at the end of each line, we
-    # had to do some convoluted checks to find out what is the current
-    # scope at the beginning of the line.  This check is simplified by
-    # saving the previous top of nesting stack.
-    #
-    # We could save the full stack, but we only need the top.  Copying
-    # the full nesting stack would slow down cpplint by ~10%.
-    self.previous_stack_top = []
-
-    # Stack of _PreprocessorInfo objects.
-    self.pp_stack = []
-
-  def SeenOpenBrace(self):
-    """Check if we have seen the opening brace for the innermost block.
-
-    Returns:
-      True if we have seen the opening brace, False if the innermost
-      block is still expecting an opening brace.
-    """
-    return (not self.stack) or self.stack[-1].seen_open_brace
-
-  def InNamespaceBody(self):
-    """Check if we are currently one level inside a namespace body.
-
-    Returns:
-      True if top of the stack is a namespace block, False otherwise.
-    """
-    return self.stack and isinstance(self.stack[-1], _NamespaceInfo)
-
-  def InExternC(self):
-    """Check if we are currently one level inside an 'extern "C"' block.
-
-    Returns:
-      True if top of the stack is an extern block, False otherwise.
-    """
-    return self.stack and isinstance(self.stack[-1], _ExternCInfo)
-
-  def InClassDeclaration(self):
-    """Check if we are currently one level inside a class or struct declaration.
-
-    Returns:
-      True if top of the stack is a class/struct, False otherwise.
-    """
-    return self.stack and isinstance(self.stack[-1], _ClassInfo)
-
-  def InAsmBlock(self):
-    """Check if we are currently one level inside an inline ASM block.
-
-    Returns:
-      True if the top of the stack is a block containing inline ASM.
-    """
-    return self.stack and self.stack[-1].inline_asm != _NO_ASM
-
-  def InTemplateArgumentList(self, clean_lines, linenum, pos):
-    """Check if current position is inside template argument list.
-
-    Args:
-      clean_lines: A CleansedLines instance containing the file.
-      linenum: The number of the line to check.
-      pos: position just after the suspected template argument.
-    Returns:
-      True if (linenum, pos) is inside template arguments.
-    """
-    while linenum < clean_lines.NumLines():
-      # Find the earliest character that might indicate a template argument
-      line = clean_lines.elided[linenum]
-      match = Match(r'^[^{};=\[\]\.<>]*(.)', line[pos:])
-      if not match:
-        linenum += 1
-        pos = 0
-        continue
-      token = match.group(1)
-      pos += len(match.group(0))
-
-      # These things do not look like template argument list:
-      #   class Suspect {
-      #   class Suspect x; }
-      if token in ('{', '}', ';'): return False
-
-      # These things look like template argument list:
-      #   template <class Suspect>
-      #   template <class Suspect = default_value>
-      #   template <class Suspect[]>
-      #   template <class Suspect...>
-      if token in ('>', '=', '[', ']', '.'): return True
-
-      # Check if token is an unmatched '<'.
-      # If not, move on to the next character.
-      if token != '<':
-        pos += 1
-        if pos >= len(line):
-          linenum += 1
-          pos = 0
-        continue
-
-      # We can't be sure if we just find a single '<', and need to
-      # find the matching '>'.
-      (_, end_line, end_pos) = CloseExpression(clean_lines, linenum, pos - 1)
-      if end_pos < 0:
-        # Not sure if template argument list or syntax error in file
-        return False
-      linenum = end_line
-      pos = end_pos
-    return False
-
-  def UpdatePreprocessor(self, line):
-    """Update preprocessor stack.
-
-    We need to handle preprocessors due to classes like this:
-      #ifdef SWIG
-      struct ResultDetailsPageElementExtensionPoint {
-      #else
-      struct ResultDetailsPageElementExtensionPoint : public Extension {
-      #endif
-
-    We make the following assumptions (good enough for most files):
-    - Preprocessor condition evaluates to true from #if up to first
-      #else/#elif/#endif.
-
-    - Preprocessor condition evaluates to false from #else/#elif up
-      to #endif.  We still perform lint checks on these lines, but
-      these do not affect nesting stack.
-
-    Args:
-      line: current line to check.
-    """
-    if Match(r'^\s*#\s*(if|ifdef|ifndef)\b', line):
-      # Beginning of #if block, save the nesting stack here.  The saved
-      # stack will allow us to restore the parsing state in the #else case.
-      self.pp_stack.append(_PreprocessorInfo(copy.deepcopy(self.stack)))
-    elif Match(r'^\s*#\s*(else|elif)\b', line):
-      # Beginning of #else block
-      if self.pp_stack:
-        if not self.pp_stack[-1].seen_else:
-          # This is the first #else or #elif block.  Remember the
-          # whole nesting stack up to this point.  This is what we
-          # keep after the #endif.
-          self.pp_stack[-1].seen_else = True
-          self.pp_stack[-1].stack_before_else = copy.deepcopy(self.stack)
-
-        # Restore the stack to how it was before the #if
-        self.stack = copy.deepcopy(self.pp_stack[-1].stack_before_if)
-      else:
-        # TODO(unknown): unexpected #else, issue warning?
-        pass
-    elif Match(r'^\s*#\s*endif\b', line):
-      # End of #if or #else blocks.
-      if self.pp_stack:
-        # If we saw an #else, we will need to restore the nesting
-        # stack to its former state before the #else, otherwise we
-        # will just continue from where we left off.
-        if self.pp_stack[-1].seen_else:
-          # Here we can just use a shallow copy since we are the last
-          # reference to it.
-          self.stack = self.pp_stack[-1].stack_before_else
-        # Drop the corresponding #if
-        self.pp_stack.pop()
-      else:
-        # TODO(unknown): unexpected #endif, issue warning?
-        pass
-
-  # TODO(unknown): Update() is too long, but we will refactor later.
-  def Update(self, filename, clean_lines, linenum, error):
-    """Update nesting state with current line.
-
-    Args:
-      filename: The name of the current file.
-      clean_lines: A CleansedLines instance containing the file.
-      linenum: The number of the line to check.
-      error: The function to call with any errors found.
-    """
-    line = clean_lines.elided[linenum]
-
-    # Remember top of the previous nesting stack.
-    #
-    # The stack is always pushed/popped and not modified in place, so
-    # we can just do a shallow copy instead of copy.deepcopy.  Using
-    # deepcopy would slow down cpplint by ~28%.
-    if self.stack:
-      self.previous_stack_top = self.stack[-1]
-    else:
-      self.previous_stack_top = None
-
-    # Update pp_stack
-    self.UpdatePreprocessor(line)
-
-    # Count parentheses.  This is to avoid adding struct arguments to
-    # the nesting stack.
-    if self.stack:
-      inner_block = self.stack[-1]
-      depth_change = line.count('(') - line.count(')')
-      inner_block.open_parentheses += depth_change
-
-      # Also check if we are starting or ending an inline assembly block.
-      if inner_block.inline_asm in (_NO_ASM, _END_ASM):
-        if (depth_change != 0 and
-            inner_block.open_parentheses == 1 and
-            _MATCH_ASM.match(line)):
-          # Enter assembly block
-          inner_block.inline_asm = _INSIDE_ASM
-        else:
-          # Not entering assembly block.  If previous line was _END_ASM,
-          # we will now shift to _NO_ASM state.
-          inner_block.inline_asm = _NO_ASM
-      elif (inner_block.inline_asm == _INSIDE_ASM and
-            inner_block.open_parentheses == 0):
-        # Exit assembly block
-        inner_block.inline_asm = _END_ASM
-
-    # Consume namespace declaration at the beginning of the line.  Do
-    # this in a loop so that we catch same line declarations like this:
-    #   namespace proto2 { namespace bridge { class MessageSet; } }
-    while True:
-      # Match start of namespace.  The "\b\s*" below catches namespace
-      # declarations even if it weren't followed by a whitespace, this
-      # is so that we don't confuse our namespace checker.  The
-      # missing spaces will be flagged by CheckSpacing.
-      namespace_decl_match = Match(r'^\s*namespace\b\s*([:\w]+)?(.*)$', line)
-      if not namespace_decl_match:
-        break
-
-      new_namespace = _NamespaceInfo(namespace_decl_match.group(1), linenum)
-      self.stack.append(new_namespace)
-
-      line = namespace_decl_match.group(2)
-      if line.find('{') != -1:
-        new_namespace.seen_open_brace = True
-        line = line[line.find('{') + 1:]
-
-    # Look for a class declaration in whatever is left of the line
-    # after parsing namespaces.  The regexp accounts for decorated classes
-    # such as in:
-    #   class LOCKABLE API Object {
-    #   };
-    class_decl_match = Match(
-        r'^(\s*(?:template\s*<[\w\s<>,:]*>\s*)?'
-        r'(class|struct)\s+(?:[A-Z_]+\s+)*(\w+(?:::\w+)*))'
-        r'(.*)$', line)
-    if (class_decl_match and
-        (not self.stack or self.stack[-1].open_parentheses == 0)):
-      # We do not want to accept classes that are actually template arguments:
-      #   template <class Ignore1,
-      #             class Ignore2 = Default<Args>,
-      #             template <Args> class Ignore3>
-      #   void Function() {};
-      #
-      # To avoid template argument cases, we scan forward and look for
-      # an unmatched '>'.  If we see one, assume we are inside a
-      # template argument list.
-      end_declaration = len(class_decl_match.group(1))
-      if not self.InTemplateArgumentList(clean_lines, linenum, end_declaration):
-        self.stack.append(_ClassInfo(
-            class_decl_match.group(3), class_decl_match.group(2),
-            clean_lines, linenum))
-        line = class_decl_match.group(4)
-
-    # If we have not yet seen the opening brace for the innermost block,
-    # run checks here.
-    if not self.SeenOpenBrace():
-      self.stack[-1].CheckBegin(filename, clean_lines, linenum, error)
-
-    # Update access control if we are inside a class/struct
-    if self.stack and isinstance(self.stack[-1], _ClassInfo):
-      classinfo = self.stack[-1]
-      access_match = Match(
-          r'^(.*)\b(public|private|protected|signals)(\s+(?:slots\s*)?)?'
-          r':(?:[^:]|$)',
-          line)
-      if access_match:
-        classinfo.access = access_match.group(2)
-
-        # Check that access keywords are indented +1 space.  Skip this
-        # check if the keywords are not preceded by whitespaces.
-        indent = access_match.group(1)
-        if (len(indent) != classinfo.class_indent + 1 and
-            Match(r'^\s*$', indent)):
-          if classinfo.is_struct:
-            parent = 'struct ' + classinfo.name
-          else:
-            parent = 'class ' + classinfo.name
-          slots = ''
-          if access_match.group(3):
-            slots = access_match.group(3)
-          error(filename, linenum, 'whitespace/indent', 3,
-                '%s%s: should be indented +1 space inside %s' % (
-                    access_match.group(2), slots, parent))
-
-    # Consume braces or semicolons from what's left of the line
-    while True:
-      # Match first brace, semicolon, or closed parenthesis.
-      matched = Match(r'^[^{;)}]*([{;)}])(.*)$', line)
-      if not matched:
-        break
-
-      token = matched.group(1)
-      if token == '{':
-        # If namespace or class hasn't seen a opening brace yet, mark
-        # namespace/class head as complete.  Push a new block onto the
-        # stack otherwise.
-        if not self.SeenOpenBrace():
-          self.stack[-1].seen_open_brace = True
-        elif Match(r'^extern\s*"[^"]*"\s*\{', line):
-          self.stack.append(_ExternCInfo())
-        else:
-          self.stack.append(_BlockInfo(True))
-          if _MATCH_ASM.match(line):
-            self.stack[-1].inline_asm = _BLOCK_ASM
-
-      elif token == ';' or token == ')':
-        # If we haven't seen an opening brace yet, but we already saw
-        # a semicolon, this is probably a forward declaration.  Pop
-        # the stack for these.
-        #
-        # Similarly, if we haven't seen an opening brace yet, but we
-        # already saw a closing parenthesis, then these are probably
-        # function arguments with extra "class" or "struct" keywords.
-        # Also pop these stack for these.
-        if not self.SeenOpenBrace():
-          self.stack.pop()
-      else:  # token == '}'
-        # Perform end of block checks and pop the stack.
-        if self.stack:
-          self.stack[-1].CheckEnd(filename, clean_lines, linenum, error)
-          self.stack.pop()
-      line = matched.group(2)
-
-  def InnermostClass(self):
-    """Get class info on the top of the stack.
-
-    Returns:
-      A _ClassInfo object if we are inside a class, or None otherwise.
-    """
-    for i in range(len(self.stack), 0, -1):
-      classinfo = self.stack[i - 1]
-      if isinstance(classinfo, _ClassInfo):
-        return classinfo
-    return None
-
-  def CheckCompletedBlocks(self, filename, error):
-    """Checks that all classes and namespaces have been completely parsed.
-
-    Call this when all lines in a file have been processed.
-    Args:
-      filename: The name of the current file.
-      error: The function to call with any errors found.
-    """
-    # Note: This test can result in false positives if #ifdef constructs
-    # get in the way of brace matching. See the testBuildClass test in
-    # cpplint_unittest.py for an example of this.
-    for obj in self.stack:
-      if isinstance(obj, _ClassInfo):
-        error(filename, obj.starting_linenum, 'build/class', 5,
-              'Failed to find complete declaration of class %s' %
-              obj.name)
-      elif isinstance(obj, _NamespaceInfo):
-        error(filename, obj.starting_linenum, 'build/namespaces', 5,
-              'Failed to find complete declaration of namespace %s' %
-              obj.name)
-
-
-def CheckForNonStandardConstructs(filename, clean_lines, linenum,
-                                  nesting_state, error):
-  r"""Logs an error if we see certain non-ANSI constructs ignored by gcc-2.
-
-  Complain about several constructs which gcc-2 accepts, but which are
-  not standard C++.  Warning about these in lint is one way to ease the
-  transition to new compilers.
-  - put storage class first (e.g. "static const" instead of "const static").
-  - "%lld" instead of %qd" in printf-type functions.
-  - "%1$d" is non-standard in printf-type functions.
-  - "\%" is an undefined character escape sequence.
-  - text after #endif is not allowed.
-  - invalid inner-style forward declaration.
-  - >? and <? operators, and their >?= and <?= cousins.
-
-  Additionally, check for constructor/destructor style violations and reference
-  members, as it is very convenient to do so while checking for
-  gcc-2 compliance.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    nesting_state: A NestingState instance which maintains information about
-                   the current stack of nested blocks being parsed.
-    error: A callable to which errors are reported, which takes 4 arguments:
-           filename, line number, error level, and message
-  """
-
-  # Remove comments from the line, but leave in strings for now.
-  line = clean_lines.lines[linenum]
-
-  if Search(r'printf\s*\(.*".*%[-+ ]?\d*q', line):
-    error(filename, linenum, 'runtime/printf_format', 3,
-          '%q in format strings is deprecated.  Use %ll instead.')
-
-  if Search(r'printf\s*\(.*".*%\d+\$', line):
-    error(filename, linenum, 'runtime/printf_format', 2,
-          '%N$ formats are unconventional.  Try rewriting to avoid them.')
-
-  # Remove escaped backslashes before looking for undefined escapes.
-  line = line.replace('\\\\', '')
-
-  if Search(r'("|\').*\\(%|\[|\(|{)', line):
-    error(filename, linenum, 'build/printf_format', 3,
-          '%, [, (, and { are undefined character escapes.  Unescape them.')
-
-  # For the rest, work with both comments and strings removed.
-  line = clean_lines.elided[linenum]
-
-  if Search(r'\b(const|volatile|void|char|short|int|long'
-            r'|float|double|signed|unsigned'
-            r'|schar|u?int8|u?int16|u?int32|u?int64)'
-            r'\s+(register|static|extern|typedef)\b',
-            line):
-    error(filename, linenum, 'build/storage_class', 5,
-          'Storage class (static, extern, typedef, etc) should be first.')
-
-  if Match(r'\s*#\s*endif\s*[^/\s]+', line):
-    error(filename, linenum, 'build/endif_comment', 5,
-          'Uncommented text after #endif is non-standard.  Use a comment.')
-
-  if Match(r'\s*class\s+(\w+\s*::\s*)+\w+\s*;', line):
-    error(filename, linenum, 'build/forward_decl', 5,
-          'Inner-style forward declarations are invalid.  Remove this line.')
-
-  if Search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?',
-            line):
-    error(filename, linenum, 'build/deprecated', 3,
-          '>? and <? (max and min) operators are non-standard and deprecated.')
-
-  if Search(r'^\s*const\s*string\s*&\s*\w+\s*;', line):
-    # TODO(unknown): Could it be expanded safely to arbitrary references,
-    # without triggering too many false positives? The first
-    # attempt triggered 5 warnings for mostly benign code in the regtest, hence
-    # the restriction.
-    # Here's the original regexp, for the reference:
-    # type_name = r'\w+((\s*::\s*\w+)|(\s*<\s*\w+?\s*>))?'
-    # r'\s*const\s*' + type_name + '\s*&\s*\w+\s*;'
-    error(filename, linenum, 'runtime/member_string_references', 2,
-          'const string& members are dangerous. It is much better to use '
-          'alternatives, such as pointers or simple constants.')
-
-  # Everything else in this function operates on class declarations.
-  # Return early if the top of the nesting stack is not a class, or if
-  # the class head is not completed yet.
-  classinfo = nesting_state.InnermostClass()
-  if not classinfo or not classinfo.seen_open_brace:
-    return
-
-  # The class may have been declared with namespace or classname qualifiers.
-  # The constructor and destructor will not have those qualifiers.
-  base_classname = classinfo.name.split('::')[-1]
-
-  # Look for single-argument constructors that aren't marked explicit.
-  # Technically a valid construct, but against style. Also look for
-  # non-single-argument constructors which are also technically valid, but
-  # strongly suggest something is wrong.
-  explicit_constructor_match = Match(
-      r'\s+(?:inline\s+)?(explicit\s+)?(?:inline\s+)?%s\s*'
-      r'\(((?:[^()]|\([^()]*\))*)\)'
-      % re.escape(base_classname),
-      line)
-
-  if explicit_constructor_match:
-    is_marked_explicit = explicit_constructor_match.group(1)
-
-    if not explicit_constructor_match.group(2):
-      constructor_args = []
-    else:
-      constructor_args = explicit_constructor_match.group(2).split(',')
-
-    # collapse arguments so that commas in template parameter lists and function
-    # argument parameter lists don't split arguments in two
-    i = 0
-    while i < len(constructor_args):
-      constructor_arg = constructor_args[i]
-      while (constructor_arg.count('<') > constructor_arg.count('>') or
-             constructor_arg.count('(') > constructor_arg.count(')')):
-        constructor_arg += ',' + constructor_args[i + 1]
-        del constructor_args[i + 1]
-      constructor_args[i] = constructor_arg
-      i += 1
-
-    defaulted_args = [arg for arg in constructor_args if '=' in arg]
-    noarg_constructor = (not constructor_args or  # empty arg list
-                         # 'void' arg specifier
-                         (len(constructor_args) == 1 and
-                          constructor_args[0].strip() == 'void'))
-    onearg_constructor = ((len(constructor_args) == 1 and  # exactly one arg
-                           not noarg_constructor) or
-                          # all but at most one arg defaulted
-                          (len(constructor_args) >= 1 and
-                           not noarg_constructor and
-                           len(defaulted_args) >= len(constructor_args) - 1))
-    initializer_list_constructor = bool(
-        onearg_constructor and
-        Search(r'\bstd\s*::\s*initializer_list\b', constructor_args[0]))
-    copy_constructor = bool(
-        onearg_constructor and
-        Match(r'(const\s+)?%s(\s*<[^>]*>)?(\s+const)?\s*(?:<\w+>\s*)?&'
-              % re.escape(base_classname), constructor_args[0].strip()))
-
-    if (not is_marked_explicit and
-        onearg_constructor and
-        not initializer_list_constructor and
-        not copy_constructor):
-      if defaulted_args:
-        error(filename, linenum, 'runtime/explicit', 5,
-              'Constructors callable with one argument '
-              'should be marked explicit.')
-      else:
-        error(filename, linenum, 'runtime/explicit', 5,
-              'Single-parameter constructors should be marked explicit.')
-    elif is_marked_explicit and not onearg_constructor:
-      if noarg_constructor:
-        error(filename, linenum, 'runtime/explicit', 5,
-              'Zero-parameter constructors should not be marked explicit.')
-      else:
-        error(filename, linenum, 'runtime/explicit', 0,
-              'Constructors that require multiple arguments '
-              'should not be marked explicit.')
-
-
-def CheckSpacingForFunctionCall(filename, clean_lines, linenum, error):
-  """Checks for the correctness of various spacing around function calls.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    error: The function to call with any errors found.
-  """
-  line = clean_lines.elided[linenum]
-
-  # Since function calls often occur inside if/for/while/switch
-  # expressions - which have their own, more liberal conventions - we
-  # first see if we should be looking inside such an expression for a
-  # function call, to which we can apply more strict standards.
-  fncall = line    # if there's no control flow construct, look at whole line
-  for pattern in (r'\bif\s*\((.*)\)\s*{',
-                  r'\bfor\s*\((.*)\)\s*{',
-                  r'\bwhile\s*\((.*)\)\s*[{;]',
-                  r'\bswitch\s*\((.*)\)\s*{'):
-    match = Search(pattern, line)
-    if match:
-      fncall = match.group(1)    # look inside the parens for function calls
-      break
-
-  # Except in if/for/while/switch, there should never be space
-  # immediately inside parens (eg "f( 3, 4 )").  We make an exception
-  # for nested parens ( (a+b) + c ).  Likewise, there should never be
-  # a space before a ( when it's a function argument.  I assume it's a
-  # function argument when the char before the whitespace is legal in
-  # a function name (alnum + _) and we're not starting a macro. Also ignore
-  # pointers and references to arrays and functions coz they're too tricky:
-  # we use a very simple way to recognize these:
-  # " (something)(maybe-something)" or
-  # " (something)(maybe-something," or
-  # " (something)[something]"
-  # Note that we assume the contents of [] to be short enough that
-  # they'll never need to wrap.
-  if (  # Ignore control structures.
-      not Search(r'\b(if|for|while|switch|return|new|delete|catch|sizeof)\b',
-                 fncall) and
-      # Ignore pointers/references to functions.
-      not Search(r' \([^)]+\)\([^)]*(\)|,$)', fncall) and
-      # Ignore pointers/references to arrays.
-      not Search(r' \([^)]+\)\[[^\]]+\]', fncall)):
-    if Search(r'\w\s*\(\s(?!\s*\\$)', fncall):      # a ( used for a fn call
-      error(filename, linenum, 'whitespace/parens', 4,
-            'Extra space after ( in function call')
-    elif Search(r'\(\s+(?!(\s*\\)|\()', fncall):
-      error(filename, linenum, 'whitespace/parens', 2,
-            'Extra space after (')
-    if (Search(r'\w\s+\(', fncall) and
-        not Search(r'#\s*define|typedef|using\s+\w+\s*=', fncall) and
-        not Search(r'\w\s+\((\w+::)*\*\w+\)\(', fncall) and
-        not Search(r'\bcase\s+\(', fncall)):
-      # TODO(unknown): Space after an operator function seem to be a common
-      # error, silence those for now by restricting them to highest verbosity.
-      if Search(r'\boperator_*\b', line):
-        error(filename, linenum, 'whitespace/parens', 0,
-              'Extra space before ( in function call')
-      else:
-        error(filename, linenum, 'whitespace/parens', 4,
-              'Extra space before ( in function call')
-    # If the ) is followed only by a newline or a { + newline, assume it's
-    # part of a control statement (if/while/etc), and don't complain
-    if Search(r'[^)]\s+\)\s*[^{\s]', fncall):
-      # If the closing parenthesis is preceded by only whitespaces,
-      # try to give a more descriptive error message.
-      if Search(r'^\s+\)', fncall):
-        error(filename, linenum, 'whitespace/parens', 2,
-              'Closing ) should be moved to the previous line')
-      else:
-        error(filename, linenum, 'whitespace/parens', 2,
-              'Extra space before )')
-
-
-def IsBlankLine(line):
-  """Returns true if the given line is blank.
-
-  We consider a line to be blank if the line is empty or consists of
-  only white spaces.
-
-  Args:
-    line: A line of a string.
-
-  Returns:
-    True, if the given line is blank.
-  """
-  return not line or line.isspace()
-
-
-def CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line,
-                                 error):
-  is_namespace_indent_item = (
-      len(nesting_state.stack) > 1 and
-      nesting_state.stack[-1].check_namespace_indentation and
-      isinstance(nesting_state.previous_stack_top, _NamespaceInfo) and
-      nesting_state.previous_stack_top == nesting_state.stack[-2])
-
-  if ShouldCheckNamespaceIndentation(nesting_state, is_namespace_indent_item,
-                                     clean_lines.elided, line):
-    CheckItemIndentationInNamespace(filename, clean_lines.elided,
-                                    line, error)
-
-
-def CheckForFunctionLengths(filename, clean_lines, linenum,
-                            function_state, error):
-  """Reports for long function bodies.
-
-  For an overview why this is done, see:
-  http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions
-
-  Uses a simplistic algorithm assuming other style guidelines
-  (especially spacing) are followed.
-  Only checks unindented functions, so class members are unchecked.
-  Trivial bodies are unchecked, so constructors with huge initializer lists
-  may be missed.
-  Blank/comment lines are not counted so as to avoid encouraging the removal
-  of vertical space and comments just to get through a lint check.
-  NOLINT *on the last line of a function* disables this check.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    function_state: Current function name and lines in body so far.
-    error: The function to call with any errors found.
-  """
-  lines = clean_lines.lines
-  line = lines[linenum]
-  joined_line = ''
-
-  starting_func = False
-  regexp = r'(\w(\w|::|\*|\&|\s)*)\('  # decls * & space::name( ...
-  match_result = Match(regexp, line)
-  if match_result:
-    # If the name is all caps and underscores, figure it's a macro and
-    # ignore it, unless it's TEST or TEST_F.
-    function_name = match_result.group(1).split()[-1]
-    if function_name == 'TEST' or function_name == 'TEST_F' or (
-        not Match(r'[A-Z_]+$', function_name)):
-      starting_func = True
-
-  if starting_func:
-    body_found = False
-    for start_linenum in xrange(linenum, clean_lines.NumLines()):
-      start_line = lines[start_linenum]
-      joined_line += ' ' + start_line.lstrip()
-      if Search(r'(;|})', start_line):  # Declarations and trivial functions
-        body_found = True
-        break                              # ... ignore
-      elif Search(r'{', start_line):
-        body_found = True
-        function = Search(r'((\w|:)*)\(', line).group(1)
-        if Match(r'TEST', function):    # Handle TEST... macros
-          parameter_regexp = Search(r'(\(.*\))', joined_line)
-          if parameter_regexp:             # Ignore bad syntax
-            function += parameter_regexp.group(1)
-        else:
-          function += '()'
-        function_state.Begin(function)
-        break
-    if not body_found:
-      # No body for the function (or evidence of a non-function) was found.
-      error(filename, linenum, 'readability/fn_size', 5,
-            'Lint failed to find start of function body.')
-  elif Match(r'^\}\s*$', line):  # function end
-    function_state.Check(error, filename, linenum)
-    function_state.End()
-  elif not Match(r'^\s*$', line):
-    function_state.Count()  # Count non-blank/non-comment lines.
-
-
-_RE_PATTERN_TODO = re.compile(r'^//(\s*)TODO(\(.+?\))?:?(\s|$)?')
-
-
-def CheckComment(line, filename, linenum, next_line_start, error):
-  """Checks for common mistakes in comments.
-
-  Args:
-    line: The line in question.
-    filename: The name of the current file.
-    linenum: The number of the line to check.
-    next_line_start: The first non-whitespace column of the next line.
-    error: The function to call with any errors found.
-  """
-  commentpos = line.find('//')
-  if commentpos != -1:
-    # Check if the // may be in quotes.  If so, ignore it
-    # Comparisons made explicit for clarity -- pylint: disable=g-explicit-bool-comparison
-    if (line.count('"', 0, commentpos) -
-        line.count('\\"', 0, commentpos)) % 2 == 0:   # not in quotes
-      # Allow one space for new scopes, two spaces otherwise:
-      if (not (Match(r'^.*{ *//', line) and next_line_start == commentpos) and
-          ((commentpos >= 1 and
-            line[commentpos-1] not in string.whitespace) or
-           (commentpos >= 2 and
-            line[commentpos-2] not in string.whitespace))):
-        error(filename, linenum, 'whitespace/comments', 2,
-              'At least two spaces is best between code and comments')
-
-      # Checks for common mistakes in TODO comments.
-      comment = line[commentpos:]
-      match = _RE_PATTERN_TODO.match(comment)
-      if match:
-        # One whitespace is correct; zero whitespace is handled elsewhere.
-        leading_whitespace = match.group(1)
-        if len(leading_whitespace) > 1:
-          error(filename, linenum, 'whitespace/todo', 2,
-                'Too many spaces before TODO')
-
-        username = match.group(2)
-        if not username:
-          error(filename, linenum, 'readability/todo', 2,
-                'Missing username in TODO; it should look like '
-                '"// TODO(my_username): Stuff."')
-
-        middle_whitespace = match.group(3)
-        # Comparisons made explicit for correctness -- pylint: disable=g-explicit-bool-comparison
-        if middle_whitespace != ' ' and middle_whitespace != '':
-          error(filename, linenum, 'whitespace/todo', 2,
-                'TODO(my_username) should be followed by a space')
-
-      # If the comment contains an alphanumeric character, there
-      # should be a space somewhere between it and the // unless
-      # it's a /// or //! Doxygen comment.
-      if (Match(r'//[^ ]*\w', comment) and
-          not Match(r'(///|//\!)(\s+|$)', comment)):
-        error(filename, linenum, 'whitespace/comments', 4,
-              'Should have a space between // and comment')
-
-
-def CheckAccess(filename, clean_lines, linenum, nesting_state, error):
-  """Checks for improper use of DISALLOW* macros.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    nesting_state: A NestingState instance which maintains information about
-                   the current stack of nested blocks being parsed.
-    error: The function to call with any errors found.
-  """
-  line = clean_lines.elided[linenum]  # get rid of comments and strings
-
-  matched = Match((r'\s*(DISALLOW_COPY_AND_ASSIGN|'
-                   r'DISALLOW_IMPLICIT_CONSTRUCTORS)'), line)
-  if not matched:
-    return
-  if nesting_state.stack and isinstance(nesting_state.stack[-1], _ClassInfo):
-    if nesting_state.stack[-1].access != 'private':
-      error(filename, linenum, 'readability/constructors', 3,
-            '%s must be in the private: section' % matched.group(1))
-
-  else:
-    # Found DISALLOW* macro outside a class declaration, or perhaps it
-    # was used inside a function when it should have been part of the
-    # class declaration.  We could issue a warning here, but it
-    # probably resulted in a compiler error already.
-    pass
-
-
-def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
-  """Checks for the correctness of various spacing issues in the code.
-
-  Things we check for: spaces around operators, spaces after
-  if/for/while/switch, no spaces around parens in function calls, two
-  spaces between code and comment, don't start a block with a blank
-  line, don't end a function with a blank line, don't add a blank line
-  after public/protected/private, don't have too many blank lines in a row.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    nesting_state: A NestingState instance which maintains information about
-                   the current stack of nested blocks being parsed.
-    error: The function to call with any errors found.
-  """
-
-  # Don't use "elided" lines here, otherwise we can't check commented lines.
-  # Don't want to use "raw" either, because we don't want to check inside C++11
-  # raw strings,
-  raw = clean_lines.lines_without_raw_strings
-  line = raw[linenum]
-
-  # Before nixing comments, check if the line is blank for no good
-  # reason.  This includes the first line after a block is opened, and
-  # blank lines at the end of a function (ie, right before a line like '}'
-  #
-  # Skip all the blank line checks if we are immediately inside a
-  # namespace body.  In other words, don't issue blank line warnings
-  # for this block:
-  #   namespace {
-  #
-  #   }
-  #
-  # A warning about missing end of namespace comments will be issued instead.
-  #
-  # Also skip blank line checks for 'extern "C"' blocks, which are formatted
-  # like namespaces.
-  if (IsBlankLine(line) and
-      not nesting_state.InNamespaceBody() and
-      not nesting_state.InExternC()):
-    elided = clean_lines.elided
-    prev_line = elided[linenum - 1]
-    prevbrace = prev_line.rfind('{')
-    # TODO(unknown): Don't complain if line before blank line, and line after,
-    #                both start with alnums and are indented the same amount.
-    #                This ignores whitespace at the start of a namespace block
-    #                because those are not usually indented.
-    if prevbrace != -1 and prev_line[prevbrace:].find('}') == -1:
-      # OK, we have a blank line at the start of a code block.  Before we
-      # complain, we check if it is an exception to the rule: The previous
-      # non-empty line has the parameters of a function header that are indented
-      # 4 spaces (because they did not fit in a 80 column line when placed on
-      # the same line as the function name).  We also check for the case where
-      # the previous line is indented 6 spaces, which may happen when the
-      # initializers of a constructor do not fit into a 80 column line.
-      exception = False
-      if Match(r' {6}\w', prev_line):  # Initializer list?
-        # We are looking for the opening column of initializer list, which
-        # should be indented 4 spaces to cause 6 space indentation afterwards.
-        search_position = linenum-2
-        while (search_position >= 0
-               and Match(r' {6}\w', elided[search_position])):
-          search_position -= 1
-        exception = (search_position >= 0
-                     and elided[search_position][:5] == '    :')
-      else:
-        # Search for the function arguments or an initializer list.  We use a
-        # simple heuristic here: If the line is indented 4 spaces; and we have a
-        # closing paren, without the opening paren, followed by an opening brace
-        # or colon (for initializer lists) we assume that it is the last line of
-        # a function header.  If we have a colon indented 4 spaces, it is an
-        # initializer list.
-        exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)',
-                           prev_line)
-                     or Match(r' {4}:', prev_line))
-
-      if not exception:
-        error(filename, linenum, 'whitespace/blank_line', 2,
-              'Redundant blank line at the start of a code block '
-              'should be deleted.')
-    # Ignore blank lines at the end of a block in a long if-else
-    # chain, like this:
-    #   if (condition1) {
-    #     // Something followed by a blank line
-    #
-    #   } else if (condition2) {
-    #     // Something else
-    #   }
-    if linenum + 1 < clean_lines.NumLines():
-      next_line = raw[linenum + 1]
-      if (next_line
-          and Match(r'\s*}', next_line)
-          and next_line.find('} else ') == -1):
-        error(filename, linenum, 'whitespace/blank_line', 3,
-              'Redundant blank line at the end of a code block '
-              'should be deleted.')
-
-    matched = Match(r'\s*(public|protected|private):', prev_line)
-    if matched:
-      error(filename, linenum, 'whitespace/blank_line', 3,
-            'Do not leave a blank line after "%s:"' % matched.group(1))
-
-  # Next, check comments
-  next_line_start = 0
-  if linenum + 1 < clean_lines.NumLines():
-    next_line = raw[linenum + 1]
-    next_line_start = len(next_line) - len(next_line.lstrip())
-  CheckComment(line, filename, linenum, next_line_start, error)
-
-  # get rid of comments and strings
-  line = clean_lines.elided[linenum]
-
-  # You shouldn't have spaces before your brackets, except maybe after
-  # 'delete []' or 'return []() {};'
-  if Search(r'\w\s+\[', line) and not Search(r'(?:delete|return)\s+\[', line):
-    error(filename, linenum, 'whitespace/braces', 5,
-          'Extra space before [')
-
-  # In range-based for, we wanted spaces before and after the colon, but
-  # not around "::" tokens that might appear.
-  if (Search(r'for *\(.*[^:]:[^: ]', line) or
-      Search(r'for *\(.*[^: ]:[^:]', line)):
-    error(filename, linenum, 'whitespace/forcolon', 2,
-          'Missing space around colon in range-based for loop')
-
-
-def CheckOperatorSpacing(filename, clean_lines, linenum, error):
-  """Checks for horizontal spacing around operators.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    error: The function to call with any errors found.
-  """
-  line = clean_lines.elided[linenum]
-
-  # Don't try to do spacing checks for operator methods.  Do this by
-  # replacing the troublesome characters with something else,
-  # preserving column position for all other characters.
-  #
-  # The replacement is done repeatedly to avoid false positives from
-  # operators that call operators.
-  while True:
-    match = Match(r'^(.*\boperator\b)(\S+)(\s*\(.*)$', line)
-    if match:
-      line = match.group(1) + ('_' * len(match.group(2))) + match.group(3)
-    else:
-      break
-
-  # We allow no-spaces around = within an if: "if ( (a=Foo()) == 0 )".
-  # Otherwise not.  Note we only check for non-spaces on *both* sides;
-  # sometimes people put non-spaces on one side when aligning ='s among
-  # many lines (not that this is behavior that I approve of...)
-  if ((Search(r'[\w.]=', line) or
-       Search(r'=[\w.]', line))
-      and not Search(r'\b(if|while|for) ', line)
-      # Operators taken from [lex.operators] in C++11 standard.
-      and not Search(r'(>=|<=|==|!=|&=|\^=|\|=|\+=|\*=|\/=|\%=)', line)
-      and not Search(r'operator=', line)):
-    error(filename, linenum, 'whitespace/operators', 4,
-          'Missing spaces around =')
-
-  # It's ok not to have spaces around binary operators like + - * /, but if
-  # there's too little whitespace, we get concerned.  It's hard to tell,
-  # though, so we punt on this one for now.  TODO.
-
-  # You should always have whitespace around binary operators.
-  #
-  # Check <= and >= first to avoid false positives with < and >, then
-  # check non-include lines for spacing around < and >.
-  #
-  # If the operator is followed by a comma, assume it's be used in a
-  # macro context and don't do any checks.  This avoids false
-  # positives.
-  #
-  # Note that && is not included here.  Those are checked separately
-  # in CheckRValueReference
-  match = Search(r'[^<>=!\s](==|!=|<=|>=|\|\|)[^<>=!\s,;\)]', line)
-  if match:
-    error(filename, linenum, 'whitespace/operators', 3,
-          'Missing spaces around %s' % match.group(1))
-  elif not Match(r'#.*include', line):
-    # Look for < that is not surrounded by spaces.  This is only
-    # triggered if both sides are missing spaces, even though
-    # technically should should flag if at least one side is missing a
-    # space.  This is done to avoid some false positives with shifts.
-    match = Match(r'^(.*[^\s<])<[^\s=<,]', line)
-    if match:
-      (_, _, end_pos) = CloseExpression(
-          clean_lines, linenum, len(match.group(1)))
-      if end_pos <= -1:
-        error(filename, linenum, 'whitespace/operators', 3,
-              'Missing spaces around <')
-
-    # Look for > that is not surrounded by spaces.  Similar to the
-    # above, we only trigger if both sides are missing spaces to avoid
-    # false positives with shifts.
-    match = Match(r'^(.*[^-\s>])>[^\s=>,]', line)
-    if match:
-      (_, _, start_pos) = ReverseCloseExpression(
-          clean_lines, linenum, len(match.group(1)))
-      if start_pos <= -1:
-        error(filename, linenum, 'whitespace/operators', 3,
-              'Missing spaces around >')
-
-  # We allow no-spaces around << when used like this: 10<<20, but
-  # not otherwise (particularly, not when used as streams)
-  #
-  # We also allow operators following an opening parenthesis, since
-  # those tend to be macros that deal with operators.
-  match = Search(r'(operator|[^\s(<])(?:L|UL|ULL|l|ul|ull)?<<([^\s,=<])', line)
-  if (match and not (match.group(1).isdigit() and match.group(2).isdigit()) and
-      not (match.group(1) == 'operator' and match.group(2) == ';')):
-    error(filename, linenum, 'whitespace/operators', 3,
-          'Missing spaces around <<')
-
-  # We allow no-spaces around >> for almost anything.  This is because
-  # C++11 allows ">>" to close nested templates, which accounts for
-  # most cases when ">>" is not followed by a space.
-  #
-  # We still warn on ">>" followed by alpha character, because that is
-  # likely due to ">>" being used for right shifts, e.g.:
-  #   value >> alpha
-  #
-  # When ">>" is used to close templates, the alphanumeric letter that
-  # follows would be part of an identifier, and there should still be
-  # a space separating the template type and the identifier.
-  #   type<type<type>> alpha
-  match = Search(r'>>[a-zA-Z_]', line)
-  if match:
-    error(filename, linenum, 'whitespace/operators', 3,
-          'Missing spaces around >>')
-
-  # There shouldn't be space around unary operators
-  match = Search(r'(!\s|~\s|[\s]--[\s;]|[\s]\+\+[\s;])', line)
-  if match:
-    error(filename, linenum, 'whitespace/operators', 4,
-          'Extra space for operator %s' % match.group(1))
-
-
-def CheckParenthesisSpacing(filename, clean_lines, linenum, error):
-  """Checks for horizontal spacing around parentheses.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    error: The function to call with any errors found.
-  """
-  line = clean_lines.elided[linenum]
-
-  # No spaces after an if, while, switch, or for
-  match = Search(r' (if\(|for\(|while\(|switch\()', line)
-  if match:
-    error(filename, linenum, 'whitespace/parens', 5,
-          'Missing space before ( in %s' % match.group(1))
-
-  # For if/for/while/switch, the left and right parens should be
-  # consistent about how many spaces are inside the parens, and
-  # there should either be zero or one spaces inside the parens.
-  # We don't want: "if ( foo)" or "if ( foo   )".
-  # Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed.
-  match = Search(r'\b(if|for|while|switch)\s*'
-                 r'\(([ ]*)(.).*[^ ]+([ ]*)\)\s*{\s*$',
-                 line)
-  if match:
-    if len(match.group(2)) != len(match.group(4)):
-      if not (match.group(3) == ';' and
-              len(match.group(2)) == 1 + len(match.group(4)) or
-              not match.group(2) and Search(r'\bfor\s*\(.*; \)', line)):
-        error(filename, linenum, 'whitespace/parens', 5,
-              'Mismatching spaces inside () in %s' % match.group(1))
-    if len(match.group(2)) not in [0, 1]:
-      error(filename, linenum, 'whitespace/parens', 5,
-            'Should have zero or one spaces inside ( and ) in %s' %
-            match.group(1))
-
-
-def CheckCommaSpacing(filename, clean_lines, linenum, error):
-  """Checks for horizontal spacing near commas and semicolons.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    error: The function to call with any errors found.
-  """
-  raw = clean_lines.lines_without_raw_strings
-  line = clean_lines.elided[linenum]
-
-  # You should always have a space after a comma (either as fn arg or operator)
-  #
-  # This does not apply when the non-space character following the
-  # comma is another comma, since the only time when that happens is
-  # for empty macro arguments.
-  #
-  # We run this check in two passes: first pass on elided lines to
-  # verify that lines contain missing whitespaces, second pass on raw
-  # lines to confirm that those missing whitespaces are not due to
-  # elided comments.
-  if (Search(r',[^,\s]', ReplaceAll(r'\boperator\s*,\s*\(', 'F(', line)) and
-      Search(r',[^,\s]', raw[linenum])):
-    error(filename, linenum, 'whitespace/comma', 3,
-          'Missing space after ,')
-
-  # You should always have a space after a semicolon
-  # except for few corner cases
-  # TODO(unknown): clarify if 'if (1) { return 1;}' is requires one more
-  # space after ;
-  if Search(r';[^\s};\\)/]', line):
-    error(filename, linenum, 'whitespace/semicolon', 3,
-          'Missing space after ;')
-
-
-def CheckBracesSpacing(filename, clean_lines, linenum, error):
-  """Checks for horizontal spacing near commas.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    error: The function to call with any errors found.
-  """
-  line = clean_lines.elided[linenum]
-
-  # Except after an opening paren, or after another opening brace (in case of
-  # an initializer list, for instance), you should have spaces before your
-  # braces. And since you should never have braces at the beginning of a line,
-  # this is an easy test.
-  match = Match(r'^(.*[^ ({>]){', line)
-  if match:
-    # Try a bit harder to check for brace initialization.  This
-    # happens in one of the following forms:
-    #   Constructor() : initializer_list_{} { ... }
-    #   Constructor{}.MemberFunction()
-    #   Type variable{};
-    #   FunctionCall(type{}, ...);
-    #   LastArgument(..., type{});
-    #   LOG(INFO) << type{} << " ...";
-    #   map_of_type[{...}] = ...;
-    #   ternary = expr ? new type{} : nullptr;
-    #   OuterTemplate<InnerTemplateConstructor<Type>{}>
-    #
-    # We check for the character following the closing brace, and
-    # silence the warning if it's one of those listed above, i.e.
-    # "{.;,)<>]:".
-    #
-    # To account for nested initializer list, we allow any number of
-    # closing braces up to "{;,)<".  We can't simply silence the
-    # warning on first sight of closing brace, because that would
-    # cause false negatives for things that are not initializer lists.
-    #   Silence this:         But not this:
-    #     Outer{                if (...) {
-    #       Inner{...}            if (...){  // Missing space before {
-    #     };                    }
-    #
-    # There is a false negative with this approach if people inserted
-    # spurious semicolons, e.g. "if (cond){};", but we will catch the
-    # spurious semicolon with a separate check.
-    (endline, endlinenum, endpos) = CloseExpression(
-        clean_lines, linenum, len(match.group(1)))
-    trailing_text = ''
-    if endpos > -1:
-      trailing_text = endline[endpos:]
-    for offset in xrange(endlinenum + 1,
-                         min(endlinenum + 3, clean_lines.NumLines() - 1)):
-      trailing_text += clean_lines.elided[offset]
-    if not Match(r'^[\s}]*[{.;,)<>\]:]', trailing_text):
-      error(filename, linenum, 'whitespace/braces', 5,
-            'Missing space before {')
-
-  # Make sure '} else {' has spaces.
-  if Search(r'}else', line):
-    error(filename, linenum, 'whitespace/braces', 5,
-          'Missing space before else')
-
-  # You shouldn't have a space before a semicolon at the end of the line.
-  # There's a special case for "for" since the style guide allows space before
-  # the semicolon there.
-  if Search(r':\s*;\s*$', line):
-    error(filename, linenum, 'whitespace/semicolon', 5,
-          'Semicolon defining empty statement. Use {} instead.')
-  elif Search(r'^\s*;\s*$', line):
-    error(filename, linenum, 'whitespace/semicolon', 5,
-          'Line contains only semicolon. If this should be an empty statement, '
-          'use {} instead.')
-  elif (Search(r'\s+;\s*$', line) and
-        not Search(r'\bfor\b', line)):
-    error(filename, linenum, 'whitespace/semicolon', 5,
-          'Extra space before last semicolon. If this should be an empty '
-          'statement, use {} instead.')
-
-
-def IsDecltype(clean_lines, linenum, column):
-  """Check if the token ending on (linenum, column) is decltype().
-
-  Args:
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: the number of the line to check.
-    column: end column of the token to check.
-  Returns:
-    True if this token is decltype() expression, False otherwise.
-  """
-  (text, _, start_col) = ReverseCloseExpression(clean_lines, linenum, column)
-  if start_col < 0:
-    return False
-  if Search(r'\bdecltype\s*$', text[0:start_col]):
-    return True
-  return False
-
-
-def IsTemplateParameterList(clean_lines, linenum, column):
-  """Check if the token ending on (linenum, column) is the end of template<>.
-
-  Args:
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: the number of the line to check.
-    column: end column of the token to check.
-  Returns:
-    True if this token is end of a template parameter list, False otherwise.
-  """
-  (_, startline, startpos) = ReverseCloseExpression(
-      clean_lines, linenum, column)
-  if (startpos > -1 and
-      Search(r'\btemplate\s*$', clean_lines.elided[startline][0:startpos])):
-    return True
-  return False
-
-
-def IsRValueType(typenames, clean_lines, nesting_state, linenum, column):
-  """Check if the token ending on (linenum, column) is a type.
-
-  Assumes that text to the right of the column is "&&" or a function
-  name.
-
-  Args:
-    typenames: set of type names from template-argument-list.
-    clean_lines: A CleansedLines instance containing the file.
-    nesting_state: A NestingState instance which maintains information about
-                   the current stack of nested blocks being parsed.
-    linenum: the number of the line to check.
-    column: end column of the token to check.
-  Returns:
-    True if this token is a type, False if we are not sure.
-  """
-  prefix = clean_lines.elided[linenum][0:column]
-
-  # Get one word to the left.  If we failed to do so, this is most
-  # likely not a type, since it's unlikely that the type name and "&&"
-  # would be split across multiple lines.
-  match = Match(r'^(.*)(\b\w+|[>*)&])\s*$', prefix)
-  if not match:
-    return False
-
-  # Check text following the token.  If it's "&&>" or "&&," or "&&...", it's
-  # most likely a rvalue reference used inside a template.
-  suffix = clean_lines.elided[linenum][column:]
-  if Match(r'&&\s*(?:[>,]|\.\.\.)', suffix):
-    return True
-
-  # Check for known types and end of templates:
-  #   int&& variable
-  #   vector<int>&& variable
-  #
-  # Because this function is called recursively, we also need to
-  # recognize pointer and reference types:
-  #   int* Function()
-  #   int& Function()
-  if (match.group(2) in typenames or
-      match.group(2) in ['char', 'char16_t', 'char32_t', 'wchar_t', 'bool',
-                         'short', 'int', 'long', 'signed', 'unsigned',
-                         'float', 'double', 'void', 'auto', '>', '*', '&']):
-    return True
-
-  # If we see a close parenthesis, look for decltype on the other side.
-  # decltype would unambiguously identify a type, anything else is
-  # probably a parenthesized expression and not a type.
-  if match.group(2) == ')':
-    return IsDecltype(
-        clean_lines, linenum, len(match.group(1)) + len(match.group(2)) - 1)
-
-  # Check for casts and cv-qualifiers.
-  #   match.group(1)  remainder
-  #   --------------  ---------
-  #   const_cast<     type&&
-  #   const           type&&
-  #   type            const&&
-  if Search(r'\b(?:const_cast\s*<|static_cast\s*<|dynamic_cast\s*<|'
-            r'reinterpret_cast\s*<|\w+\s)\s*$',
-            match.group(1)):
-    return True
-
-  # Look for a preceding symbol that might help differentiate the context.
-  # These are the cases that would be ambiguous:
-  #   match.group(1)  remainder
-  #   --------------  ---------
-  #   Call         (   expression &&
-  #   Declaration  (   type&&
-  #   sizeof       (   type&&
-  #   if           (   expression &&
-  #   while        (   expression &&
-  #   for          (   type&&
-  #   for(         ;   expression &&
-  #   statement    ;   type&&
-  #   block        {   type&&
-  #   constructor  {   expression &&
-  start = linenum
-  line = match.group(1)
-  match_symbol = None
-  while start >= 0:
-    # We want to skip over identifiers and commas to get to a symbol.
-    # Commas are skipped so that we can find the opening parenthesis
-    # for function parameter lists.
-    match_symbol = Match(r'^(.*)([^\w\s,])[\w\s,]*$', line)
-    if match_symbol:
-      break
-    start -= 1
-    line = clean_lines.elided[start]
-
-  if not match_symbol:
-    # Probably the first statement in the file is an rvalue reference
-    return True
-
-  if match_symbol.group(2) == '}':
-    # Found closing brace, probably an indicate of this:
-    #   block{} type&&
-    return True
-
-  if match_symbol.group(2) == ';':
-    # Found semicolon, probably one of these:
-    #   for(; expression &&
-    #   statement; type&&
-
-    # Look for the previous 'for(' in the previous lines.
-    before_text = match_symbol.group(1)
-    for i in xrange(start - 1, max(start - 6, 0), -1):
-      before_text = clean_lines.elided[i] + before_text
-    if Search(r'for\s*\([^{};]*$', before_text):
-      # This is the condition inside a for-loop
-      return False
-
-    # Did not find a for-init-statement before this semicolon, so this
-    # is probably a new statement and not a condition.
-    return True
-
-  if match_symbol.group(2) == '{':
-    # Found opening brace, probably one of these:
-    #   block{ type&& = ... ; }
-    #   constructor{ expression && expression }
-
-    # Look for a closing brace or a semicolon.  If we see a semicolon
-    # first, this is probably a rvalue reference.
-    line = clean_lines.elided[start][0:len(match_symbol.group(1)) + 1]
-    end = start
-    depth = 1
-    while True:
-      for ch in line:
-        if ch == ';':
-          return True
-        elif ch == '{':
-          depth += 1
-        elif ch == '}':
-          depth -= 1
-          if depth == 0:
-            return False
-      end += 1
-      if end >= clean_lines.NumLines():
-        break
-      line = clean_lines.elided[end]
-    # Incomplete program?
-    return False
-
-  if match_symbol.group(2) == '(':
-    # Opening parenthesis.  Need to check what's to the left of the
-    # parenthesis.  Look back one extra line for additional context.
-    before_text = match_symbol.group(1)
-    if linenum > 1:
-      before_text = clean_lines.elided[linenum - 1] + before_text
-    before_text = match_symbol.group(1)
-
-    # Patterns that are likely to be types:
-    #   [](type&&
-    #   for (type&&
-    #   sizeof(type&&
-    #   operator=(type&&
-    #
-    if Search(r'(?:\]|\bfor|\bsizeof|\boperator\s*\S+\s*)\s*$', before_text):
-      return True
-
-    # Patterns that are likely to be expressions:
-    #   if (expression &&
-    #   while (expression &&
-    #   : initializer(expression &&
-    #   , initializer(expression &&
-    #   ( FunctionCall(expression &&
-    #   + FunctionCall(expression &&
-    #   + (expression &&
-    #
-    # The last '+' represents operators such as '+' and '-'.
-    if Search(r'(?:\bif|\bwhile|[-+=%^(<!?:,&*]\s*)$', before_text):
-      return False
-
-    # Something else.  Check that tokens to the left look like
-    #   return_type function_name
-    match_func = Match(r'^(.*\S.*)\s+\w(?:\w|::)*(?:<[^<>]*>)?\s*$',
-                       match_symbol.group(1))
-    if match_func:
-      # Check for constructors, which don't have return types.
-      if Search(r'\b(?:explicit|inline)$', match_func.group(1)):
-        return True
-      implicit_constructor = Match(r'\s*(\w+)\((?:const\s+)?(\w+)', prefix)
-      if (implicit_constructor and
-          implicit_constructor.group(1) == implicit_constructor.group(2)):
-        return True
-      return IsRValueType(typenames, clean_lines, nesting_state, linenum,
-                          len(match_func.group(1)))
-
-    # Nothing before the function name.  If this is inside a block scope,
-    # this is probably a function call.
-    return not (nesting_state.previous_stack_top and
-                nesting_state.previous_stack_top.IsBlockInfo())
-
-  if match_symbol.group(2) == '>':
-    # Possibly a closing bracket, check that what's on the other side
-    # looks like the start of a template.
-    return IsTemplateParameterList(
-        clean_lines, start, len(match_symbol.group(1)))
-
-  # Some other symbol, usually something like "a=b&&c".  This is most
-  # likely not a type.
-  return False
-
-
-def IsDeletedOrDefault(clean_lines, linenum):
-  """Check if current constructor or operator is deleted or default.
-
-  Args:
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-  Returns:
-    True if this is a deleted or default constructor.
-  """
-  open_paren = clean_lines.elided[linenum].find('(')
-  if open_paren < 0:
-    return False
-  (close_line, _, close_paren) = CloseExpression(
-      clean_lines, linenum, open_paren)
-  if close_paren < 0:
-    return False
-  return Match(r'\s*=\s*(?:delete|default)\b', close_line[close_paren:])
-
-
-def IsRValueAllowed(clean_lines, linenum, typenames):
-  """Check if RValue reference is allowed on a particular line.
-
-  Args:
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    typenames: set of type names from template-argument-list.
-  Returns:
-    True if line is within the region where RValue references are allowed.
-  """
-  # Allow region marked by PUSH/POP macros
-  for i in xrange(linenum, 0, -1):
-    line = clean_lines.elided[i]
-    if Match(r'GOOGLE_ALLOW_RVALUE_REFERENCES_(?:PUSH|POP)', line):
-      if not line.endswith('PUSH'):
-        return False
-      for j in xrange(linenum, clean_lines.NumLines(), 1):
-        line = clean_lines.elided[j]
-        if Match(r'GOOGLE_ALLOW_RVALUE_REFERENCES_(?:PUSH|POP)', line):
-          return line.endswith('POP')
-
-  # Allow operator=
-  line = clean_lines.elided[linenum]
-  if Search(r'\boperator\s*=\s*\(', line):
-    return IsDeletedOrDefault(clean_lines, linenum)
-
-  # Allow constructors
-  match = Match(r'\s*(?:[\w<>]+::)*([\w<>]+)\s*::\s*([\w<>]+)\s*\(', line)
-  if match and match.group(1) == match.group(2):
-    return IsDeletedOrDefault(clean_lines, linenum)
-  if Search(r'\b(?:explicit|inline)\s+[\w<>]+\s*\(', line):
-    return IsDeletedOrDefault(clean_lines, linenum)
-
-  if Match(r'\s*[\w<>]+\s*\(', line):
-    previous_line = 'ReturnType'
-    if linenum > 0:
-      previous_line = clean_lines.elided[linenum - 1]
-    if Match(r'^\s*$', previous_line) or Search(r'[{}:;]\s*$', previous_line):
-      return IsDeletedOrDefault(clean_lines, linenum)
-
-  # Reject types not mentioned in template-argument-list
-  while line:
-    match = Match(r'^.*?(\w+)\s*&&(.*)$', line)
-    if not match:
-      break
-    if match.group(1) not in typenames:
-      return False
-    line = match.group(2)
-
-  # All RValue types that were in template-argument-list should have
-  # been removed by now.  Those were allowed, assuming that they will
-  # be forwarded.
-  #
-  # If there are no remaining RValue types left (i.e. types that were
-  # not found in template-argument-list), flag those as not allowed.
-  return line.find('&&') < 0
-
-
-def GetTemplateArgs(clean_lines, linenum):
-  """Find list of template arguments associated with this function declaration.
-
-  Args:
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: Line number containing the start of the function declaration,
-             usually one line after the end of the template-argument-list.
-  Returns:
-    Set of type names, or empty set if this does not appear to have
-    any template parameters.
-  """
-  # Find start of function
-  func_line = linenum
-  while func_line > 0:
-    line = clean_lines.elided[func_line]
-    if Match(r'^\s*$', line):
-      return set()
-    if line.find('(') >= 0:
-      break
-    func_line -= 1
-  if func_line == 0:
-    return set()
-
-  # Collapse template-argument-list into a single string
-  argument_list = ''
-  match = Match(r'^(\s*template\s*)<', clean_lines.elided[func_line])
-  if match:
-    # template-argument-list on the same line as function name
-    start_col = len(match.group(1))
-    _, end_line, end_col = CloseExpression(clean_lines, func_line, start_col)
-    if end_col > -1 and end_line == func_line:
-      start_col += 1  # Skip the opening bracket
-      argument_list = clean_lines.elided[func_line][start_col:end_col]
-
-  elif func_line > 1:
-    # template-argument-list one line before function name
-    match = Match(r'^(.*)>\s*$', clean_lines.elided[func_line - 1])
-    if match:
-      end_col = len(match.group(1))
-      _, start_line, start_col = ReverseCloseExpression(
-          clean_lines, func_line - 1, end_col)
-      if start_col > -1:
-        start_col += 1  # Skip the opening bracket
-        while start_line < func_line - 1:
-          argument_list += clean_lines.elided[start_line][start_col:]
-          start_col = 0
-          start_line += 1
-        argument_list += clean_lines.elided[func_line - 1][start_col:end_col]
-
-  if not argument_list:
-    return set()
-
-  # Extract type names
-  typenames = set()
-  while True:
-    match = Match(r'^[,\s]*(?:typename|class)(?:\.\.\.)?\s+(\w+)(.*)$',
-                  argument_list)
-    if not match:
-      break
-    typenames.add(match.group(1))
-    argument_list = match.group(2)
-  return typenames
-
-
-def CheckRValueReference(filename, clean_lines, linenum, nesting_state, error):
-  """Check for rvalue references.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    nesting_state: A NestingState instance which maintains information about
-                   the current stack of nested blocks being parsed.
-    error: The function to call with any errors found.
-  """
-  # Find lines missing spaces around &&.
-  # TODO(unknown): currently we don't check for rvalue references
-  # with spaces surrounding the && to avoid false positives with
-  # boolean expressions.
-  line = clean_lines.elided[linenum]
-  match = Match(r'^(.*\S)&&', line)
-  if not match:
-    match = Match(r'(.*)&&\S', line)
-  if (not match) or '(&&)' in line or Search(r'\boperator\s*$', match.group(1)):
-    return
-
-  # Either poorly formed && or an rvalue reference, check the context
-  # to get a more accurate error message.  Mostly we want to determine
-  # if what's to the left of "&&" is a type or not.
-  typenames = GetTemplateArgs(clean_lines, linenum)
-  and_pos = len(match.group(1))
-  if IsRValueType(typenames, clean_lines, nesting_state, linenum, and_pos):
-    if not IsRValueAllowed(clean_lines, linenum, typenames):
-      error(filename, linenum, 'build/c++11', 3,
-            'RValue references are an unapproved C++ feature.')
-  else:
-    error(filename, linenum, 'whitespace/operators', 3,
-          'Missing spaces around &&')
-
-
-def CheckSectionSpacing(filename, clean_lines, class_info, linenum, error):
-  """Checks for additional blank line issues related to sections.
-
-  Currently the only thing checked here is blank line before protected/private.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    class_info: A _ClassInfo objects.
-    linenum: The number of the line to check.
-    error: The function to call with any errors found.
-  """
-  # Skip checks if the class is small, where small means 25 lines or less.
-  # 25 lines seems like a good cutoff since that's the usual height of
-  # terminals, and any class that can't fit in one screen can't really
-  # be considered "small".
-  #
-  # Also skip checks if we are on the first line.  This accounts for
-  # classes that look like
-  #   class Foo { public: ... };
-  #
-  # If we didn't find the end of the class, last_line would be zero,
-  # and the check will be skipped by the first condition.
-  if (class_info.last_line - class_info.starting_linenum <= 24 or
-      linenum <= class_info.starting_linenum):
-    return
-
-  matched = Match(r'\s*(public|protected|private):', clean_lines.lines[linenum])
-  if matched:
-    # Issue warning if the line before public/protected/private was
-    # not a blank line, but don't do this if the previous line contains
-    # "class" or "struct".  This can happen two ways:
-    #  - We are at the beginning of the class.
-    #  - We are forward-declaring an inner class that is semantically
-    #    private, but needed to be public for implementation reasons.
-    # Also ignores cases where the previous line ends with a backslash as can be
-    # common when defining classes in C macros.
-    prev_line = clean_lines.lines[linenum - 1]
-    if (not IsBlankLine(prev_line) and
-        not Search(r'\b(class|struct)\b', prev_line) and
-        not Search(r'\\$', prev_line)):
-      # Try a bit harder to find the beginning of the class.  This is to
-      # account for multi-line base-specifier lists, e.g.:
-      #   class Derived
-      #       : public Base {
-      end_class_head = class_info.starting_linenum
-      for i in range(class_info.starting_linenum, linenum):
-        if Search(r'\{\s*$', clean_lines.lines[i]):
-          end_class_head = i
-          break
-      if end_class_head < linenum - 1:
-        error(filename, linenum, 'whitespace/blank_line', 3,
-              '"%s:" should be preceded by a blank line' % matched.group(1))
-
-
-def GetPreviousNonBlankLine(clean_lines, linenum):
-  """Return the most recent non-blank line and its line number.
-
-  Args:
-    clean_lines: A CleansedLines instance containing the file contents.
-    linenum: The number of the line to check.
-
-  Returns:
-    A tuple with two elements.  The first element is the contents of the last
-    non-blank line before the current line, or the empty string if this is the
-    first non-blank line.  The second is the line number of that line, or -1
-    if this is the first non-blank line.
-  """
-
-  prevlinenum = linenum - 1
-  while prevlinenum >= 0:
-    prevline = clean_lines.elided[prevlinenum]
-    if not IsBlankLine(prevline):     # if not a blank line...
-      return (prevline, prevlinenum)
-    prevlinenum -= 1
-  return ('', -1)
-
-
-def CheckBraces(filename, clean_lines, linenum, error):
-  """Looks for misplaced braces (e.g. at the end of line).
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    error: The function to call with any errors found.
-  """
-
-  line = clean_lines.elided[linenum]        # get rid of comments and strings
-
-  if Match(r'\s*{\s*$', line):
-    # We allow an open brace to start a line in the case where someone is using
-    # braces in a block to explicitly create a new scope, which is commonly used
-    # to control the lifetime of stack-allocated variables.  Braces are also
-    # used for brace initializers inside function calls.  We don't detect this
-    # perfectly: we just don't complain if the last non-whitespace character on
-    # the previous non-blank line is ',', ';', ':', '(', '{', or '}', or if the
-    # previous line starts a preprocessor block.
-    prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
-    if (not Search(r'[,;:}{(]\s*$', prevline) and
-        not Match(r'\s*#', prevline)):
-      error(filename, linenum, 'whitespace/braces', 4,
-            '{ should almost always be at the end of the previous line')
-
-  # An else clause should be on the same line as the preceding closing brace.
-  if Match(r'\s*else\b\s*(?:if\b|\{|$)', line):
-    prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
-    if Match(r'\s*}\s*$', prevline):
-      error(filename, linenum, 'whitespace/newline', 4,
-            'An else should appear on the same line as the preceding }')
-
-  # If braces come on one side of an else, they should be on both.
-  # However, we have to worry about "else if" that spans multiple lines!
-  if Search(r'else if\s*\(', line):       # could be multi-line if
-    brace_on_left = bool(Search(r'}\s*else if\s*\(', line))
-    # find the ( after the if
-    pos = line.find('else if')
-    pos = line.find('(', pos)
-    if pos > 0:
-      (endline, _, endpos) = CloseExpression(clean_lines, linenum, pos)
-      brace_on_right = endline[endpos:].find('{') != -1
-      if brace_on_left != brace_on_right:    # must be brace after if
-        error(filename, linenum, 'readability/braces', 5,
-              'If an else has a brace on one side, it should have it on both')
-  elif Search(r'}\s*else[^{]*$', line) or Match(r'[^}]*else\s*{', line):
-    error(filename, linenum, 'readability/braces', 5,
-          'If an else has a brace on one side, it should have it on both')
-
-  # Likewise, an else should never have the else clause on the same line
-  if Search(r'\belse [^\s{]', line) and not Search(r'\belse if\b', line):
-    error(filename, linenum, 'whitespace/newline', 4,
-          'Else clause should never be on same line as else (use 2 lines)')
-
-  # In the same way, a do/while should never be on one line
-  if Match(r'\s*do [^\s{]', line):
-    error(filename, linenum, 'whitespace/newline', 4,
-          'do/while clauses should not be on a single line')
-
-  # Check single-line if/else bodies. The style guide says 'curly braces are not
-  # required for single-line statements'. We additionally allow multi-line,
-  # single statements, but we reject anything with more than one semicolon in
-  # it. This means that the first semicolon after the if should be at the end of
-  # its line, and the line after that should have an indent level equal to or
-  # lower than the if. We also check for ambiguous if/else nesting without
-  # braces.
-  if_else_match = Search(r'\b(if\s*\(|else\b)', line)
-  if if_else_match and not Match(r'\s*#', line):
-    if_indent = GetIndentLevel(line)
-    endline, endlinenum, endpos = line, linenum, if_else_match.end()
-    if_match = Search(r'\bif\s*\(', line)
-    if if_match:
-      # This could be a multiline if condition, so find the end first.
-      pos = if_match.end() - 1
-      (endline, endlinenum, endpos) = CloseExpression(clean_lines, linenum, pos)
-    # Check for an opening brace, either directly after the if or on the next
-    # line. If found, this isn't a single-statement conditional.
-    if (not Match(r'\s*{', endline[endpos:])
-        and not (Match(r'\s*$', endline[endpos:])
-                 and endlinenum < (len(clean_lines.elided) - 1)
-                 and Match(r'\s*{', clean_lines.elided[endlinenum + 1]))):
-      while (endlinenum < len(clean_lines.elided)
-             and ';' not in clean_lines.elided[endlinenum][endpos:]):
-        endlinenum += 1
-        endpos = 0
-      if endlinenum < len(clean_lines.elided):
-        endline = clean_lines.elided[endlinenum]
-        # We allow a mix of whitespace and closing braces (e.g. for one-liner
-        # methods) and a single \ after the semicolon (for macros)
-        endpos = endline.find(';')
-        if not Match(r';[\s}]*(\\?)$', endline[endpos:]):
-          # Semicolon isn't the last character, there's something trailing.
-          # Output a warning if the semicolon is not contained inside
-          # a lambda expression.
-          if not Match(r'^[^{};]*\[[^\[\]]*\][^{}]*\{[^{}]*\}\s*\)*[;,]\s*$',
-                       endline):
-            error(filename, linenum, 'readability/braces', 4,
-                  'If/else bodies with multiple statements require braces')
-        elif endlinenum < len(clean_lines.elided) - 1:
-          # Make sure the next line is dedented
-          next_line = clean_lines.elided[endlinenum + 1]
-          next_indent = GetIndentLevel(next_line)
-          # With ambiguous nested if statements, this will error out on the
-          # if that *doesn't* match the else, regardless of whether it's the
-          # inner one or outer one.
-          if (if_match and Match(r'\s*else\b', next_line)
-              and next_indent != if_indent):
-            error(filename, linenum, 'readability/braces', 4,
-                  'Else clause should be indented at the same level as if. '
-                  'Ambiguous nested if/else chains require braces.')
-          elif next_indent > if_indent:
-            error(filename, linenum, 'readability/braces', 4,
-                  'If/else bodies with multiple statements require braces')
-
-
-def CheckTrailingSemicolon(filename, clean_lines, linenum, error):
-  """Looks for redundant trailing semicolon.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    error: The function to call with any errors found.
-  """
-
-  line = clean_lines.elided[linenum]
-
-  # Block bodies should not be followed by a semicolon.  Due to C++11
-  # brace initialization, there are more places where semicolons are
-  # required than not, so we use a whitelist approach to check these
-  # rather than a blacklist.  These are the places where "};" should
-  # be replaced by just "}":
-  # 1. Some flavor of block following closing parenthesis:
-  #    for (;;) {};
-  #    while (...) {};
-  #    switch (...) {};
-  #    Function(...) {};
-  #    if (...) {};
-  #    if (...) else if (...) {};
-  #
-  # 2. else block:
-  #    if (...) else {};
-  #
-  # 3. const member function:
-  #    Function(...) const {};
-  #
-  # 4. Block following some statement:
-  #    x = 42;
-  #    {};
-  #
-  # 5. Block at the beginning of a function:
-  #    Function(...) {
-  #      {};
-  #    }
-  #
-  #    Note that naively checking for the preceding "{" will also match
-  #    braces inside multi-dimensional arrays, but this is fine since
-  #    that expression will not contain semicolons.
-  #
-  # 6. Block following another block:
-  #    while (true) {}
-  #    {};
-  #
-  # 7. End of namespaces:
-  #    namespace {};
-  #
-  #    These semicolons seems far more common than other kinds of
-  #    redundant semicolons, possibly due to people converting classes
-  #    to namespaces.  For now we do not warn for this case.
-  #
-  # Try matching case 1 first.
-  match = Match(r'^(.*\)\s*)\{', line)
-  if match:
-    # Matched closing parenthesis (case 1).  Check the token before the
-    # matching opening parenthesis, and don't warn if it looks like a
-    # macro.  This avoids these false positives:
-    #  - macro that defines a base class
-    #  - multi-line macro that defines a base class
-    #  - macro that defines the whole class-head
-    #
-    # But we still issue warnings for macros that we know are safe to
-    # warn, specifically:
-    #  - TEST, TEST_F, TEST_P, MATCHER, MATCHER_P
-    #  - TYPED_TEST
-    #  - INTERFACE_DEF
-    #  - EXCLUSIVE_LOCKS_REQUIRED, SHARED_LOCKS_REQUIRED, LOCKS_EXCLUDED:
-    #
-    # We implement a whitelist of safe macros instead of a blacklist of
-    # unsafe macros, even though the latter appears less frequently in
-    # google code and would have been easier to implement.  This is because
-    # the downside for getting the whitelist wrong means some extra
-    # semicolons, while the downside for getting the blacklist wrong
-    # would result in compile errors.
-    #
-    # In addition to macros, we also don't want to warn on
-    #  - Compound literals
-    #  - Lambdas
-    #  - alignas specifier with anonymous structs:
-    closing_brace_pos = match.group(1).rfind(')')
-    opening_parenthesis = ReverseCloseExpression(
-        clean_lines, linenum, closing_brace_pos)
-    if opening_parenthesis[2] > -1:
-      line_prefix = opening_parenthesis[0][0:opening_parenthesis[2]]
-      macro = Search(r'\b([A-Z_]+)\s*$', line_prefix)
-      func = Match(r'^(.*\])\s*$', line_prefix)
-      if ((macro and
-           macro.group(1) not in (
-               'TEST', 'TEST_F', 'MATCHER', 'MATCHER_P', 'TYPED_TEST',
-               'EXCLUSIVE_LOCKS_REQUIRED', 'SHARED_LOCKS_REQUIRED',
-               'LOCKS_EXCLUDED', 'INTERFACE_DEF')) or
-          (func and not Search(r'\boperator\s*\[\s*\]', func.group(1))) or
-          Search(r'\b(?:struct|union)\s+alignas\s*$', line_prefix) or
-          Search(r'\s+=\s*$', line_prefix)):
-        match = None
-    if (match and
-        opening_parenthesis[1] > 1 and
-        Search(r'\]\s*$', clean_lines.elided[opening_parenthesis[1] - 1])):
-      # Multi-line lambda-expression
-      match = None
-
-  else:
-    # Try matching cases 2-3.
-    match = Match(r'^(.*(?:else|\)\s*const)\s*)\{', line)
-    if not match:
-      # Try matching cases 4-6.  These are always matched on separate lines.
-      #
-      # Note that we can't simply concatenate the previous line to the
-      # current line and do a single match, otherwise we may output
-      # duplicate warnings for the blank line case:
-      #   if (cond) {
-      #     // blank line
-      #   }
-      prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
-      if prevline and Search(r'[;{}]\s*$', prevline):
-        match = Match(r'^(\s*)\{', line)
-
-  # Check matching closing brace
-  if match:
-    (endline, endlinenum, endpos) = CloseExpression(
-        clean_lines, linenum, len(match.group(1)))
-    if endpos > -1 and Match(r'^\s*;', endline[endpos:]):
-      # Current {} pair is eligible for semicolon check, and we have found
-      # the redundant semicolon, output warning here.
-      #
-      # Note: because we are scanning forward for opening braces, and
-      # outputting warnings for the matching closing brace, if there are
-      # nested blocks with trailing semicolons, we will get the error
-      # messages in reversed order.
-      error(filename, endlinenum, 'readability/braces', 4,
-            "You don't need a ; after a }")
-
-
-def CheckEmptyBlockBody(filename, clean_lines, linenum, error):
-  """Look for empty loop/conditional body with only a single semicolon.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    error: The function to call with any errors found.
-  """
-
-  # Search for loop keywords at the beginning of the line.  Because only
-  # whitespaces are allowed before the keywords, this will also ignore most
-  # do-while-loops, since those lines should start with closing brace.
-  #
-  # We also check "if" blocks here, since an empty conditional block
-  # is likely an error.
-  line = clean_lines.elided[linenum]
-  matched = Match(r'\s*(for|while|if)\s*\(', line)
-  if matched:
-    # Find the end of the conditional expression
-    (end_line, end_linenum, end_pos) = CloseExpression(
-        clean_lines, linenum, line.find('('))
-
-    # Output warning if what follows the condition expression is a semicolon.
-    # No warning for all other cases, including whitespace or newline, since we
-    # have a separate check for semicolons preceded by whitespace.
-    if end_pos >= 0 and Match(r';', end_line[end_pos:]):
-      if matched.group(1) == 'if':
-        error(filename, end_linenum, 'whitespace/empty_conditional_body', 5,
-              'Empty conditional bodies should use {}')
-      else:
-        error(filename, end_linenum, 'whitespace/empty_loop_body', 5,
-              'Empty loop bodies should use {} or continue')
-
-
-def FindCheckMacro(line):
-  """Find a replaceable CHECK-like macro.
-
-  Args:
-    line: line to search on.
-  Returns:
-    (macro name, start position), or (None, -1) if no replaceable
-    macro is found.
-  """
-  for macro in _CHECK_MACROS:
-    i = line.find(macro)
-    if i >= 0:
-      # Find opening parenthesis.  Do a regular expression match here
-      # to make sure that we are matching the expected CHECK macro, as
-      # opposed to some other macro that happens to contain the CHECK
-      # substring.
-      matched = Match(r'^(.*\b' + macro + r'\s*)\(', line)
-      if not matched:
-        continue
-      return (macro, len(matched.group(1)))
-  return (None, -1)
-
-
-def CheckCheck(filename, clean_lines, linenum, error):
-  """Checks the use of CHECK and EXPECT macros.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    error: The function to call with any errors found.
-  """
-
-  # Decide the set of replacement macros that should be suggested
-  lines = clean_lines.elided
-  (check_macro, start_pos) = FindCheckMacro(lines[linenum])
-  if not check_macro:
-    return
-
-  # Find end of the boolean expression by matching parentheses
-  (last_line, end_line, end_pos) = CloseExpression(
-      clean_lines, linenum, start_pos)
-  if end_pos < 0:
-    return
-
-  # If the check macro is followed by something other than a
-  # semicolon, assume users will log their own custom error messages
-  # and don't suggest any replacements.
-  if not Match(r'\s*;', last_line[end_pos:]):
-    return
-
-  if linenum == end_line:
-    expression = lines[linenum][start_pos + 1:end_pos - 1]
-  else:
-    expression = lines[linenum][start_pos + 1:]
-    for i in xrange(linenum + 1, end_line):
-      expression += lines[i]
-    expression += last_line[0:end_pos - 1]
-
-  # Parse expression so that we can take parentheses into account.
-  # This avoids false positives for inputs like "CHECK((a < 4) == b)",
-  # which is not replaceable by CHECK_LE.
-  lhs = ''
-  rhs = ''
-  operator = None
-  while expression:
-    matched = Match(r'^\s*(<<|<<=|>>|>>=|->\*|->|&&|\|\||'
-                    r'==|!=|>=|>|<=|<|\()(.*)$', expression)
-    if matched:
-      token = matched.group(1)
-      if token == '(':
-        # Parenthesized operand
-        expression = matched.group(2)
-        (end, _) = FindEndOfExpressionInLine(expression, 0, ['('])
-        if end < 0:
-          return  # Unmatched parenthesis
-        lhs += '(' + expression[0:end]
-        expression = expression[end:]
-      elif token in ('&&', '||'):
-        # Logical and/or operators.  This means the expression
-        # contains more than one term, for example:
-        #   CHECK(42 < a && a < b);
-        #
-        # These are not replaceable with CHECK_LE, so bail out early.
-        return
-      elif token in ('<<', '<<=', '>>', '>>=', '->*', '->'):
-        # Non-relational operator
-        lhs += token
-        expression = matched.group(2)
-      else:
-        # Relational operator
-        operator = token
-        rhs = matched.group(2)
-        break
-    else:
-      # Unparenthesized operand.  Instead of appending to lhs one character
-      # at a time, we do another regular expression match to consume several
-      # characters at once if possible.  Trivial benchmark shows that this
-      # is more efficient when the operands are longer than a single
-      # character, which is generally the case.
-      matched = Match(r'^([^-=!<>()&|]+)(.*)$', expression)
-      if not matched:
-        matched = Match(r'^(\s*\S)(.*)$', expression)
-        if not matched:
-          break
-      lhs += matched.group(1)
-      expression = matched.group(2)
-
-  # Only apply checks if we got all parts of the boolean expression
-  if not (lhs and operator and rhs):
-    return
-
-  # Check that rhs do not contain logical operators.  We already know
-  # that lhs is fine since the loop above parses out && and ||.
-  if rhs.find('&&') > -1 or rhs.find('||') > -1:
-    return
-
-  # At least one of the operands must be a constant literal.  This is
-  # to avoid suggesting replacements for unprintable things like
-  # CHECK(variable != iterator)
-  #
-  # The following pattern matches decimal, hex integers, strings, and
-  # characters (in that order).
-  lhs = lhs.strip()
-  rhs = rhs.strip()
-  match_constant = r'^([-+]?(\d+|0[xX][0-9a-fA-F]+)[lLuU]{0,3}|".*"|\'.*\')$'
-  if Match(match_constant, lhs) or Match(match_constant, rhs):
-    # Note: since we know both lhs and rhs, we can provide a more
-    # descriptive error message like:
-    #   Consider using CHECK_EQ(x, 42) instead of CHECK(x == 42)
-    # Instead of:
-    #   Consider using CHECK_EQ instead of CHECK(a == b)
-    #
-    # We are still keeping the less descriptive message because if lhs
-    # or rhs gets long, the error message might become unreadable.
-    error(filename, linenum, 'readability/check', 2,
-          'Consider using %s instead of %s(a %s b)' % (
-              _CHECK_REPLACEMENT[check_macro][operator],
-              check_macro, operator))
-
-
-def CheckAltTokens(filename, clean_lines, linenum, error):
-  """Check alternative keywords being used in boolean expressions.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    error: The function to call with any errors found.
-  """
-  line = clean_lines.elided[linenum]
-
-  # Avoid preprocessor lines
-  if Match(r'^\s*#', line):
-    return
-
-  # Last ditch effort to avoid multi-line comments.  This will not help
-  # if the comment started before the current line or ended after the
-  # current line, but it catches most of the false positives.  At least,
-  # it provides a way to workaround this warning for people who use
-  # multi-line comments in preprocessor macros.
-  #
-  # TODO(unknown): remove this once cpplint has better support for
-  # multi-line comments.
-  if line.find('/*') >= 0 or line.find('*/') >= 0:
-    return
-
-  for match in _ALT_TOKEN_REPLACEMENT_PATTERN.finditer(line):
-    error(filename, linenum, 'readability/alt_tokens', 2,
-          'Use operator %s instead of %s' % (
-              _ALT_TOKEN_REPLACEMENT[match.group(1)], match.group(1)))
-
-
-def GetLineWidth(line):
-  """Determines the width of the line in column positions.
-
-  Args:
-    line: A string, which may be a Unicode string.
-
-  Returns:
-    The width of the line in column positions, accounting for Unicode
-    combining characters and wide characters.
-  """
-  if isinstance(line, unicode):
-    width = 0
-    for uc in unicodedata.normalize('NFC', line):
-      if unicodedata.east_asian_width(uc) in ('W', 'F'):
-        width += 2
-      elif not unicodedata.combining(uc):
-        width += 1
-    return width
-  else:
-    return len(line)
-
-
-def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
-               error):
-  """Checks rules from the 'C++ style rules' section of cppguide.html.
-
-  Most of these rules are hard to test (naming, comment style), but we
-  do what we can.  In particular we check for 2-space indents, line lengths,
-  tab usage, spaces inside code, etc.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    file_extension: The extension (without the dot) of the filename.
-    nesting_state: A NestingState instance which maintains information about
-                   the current stack of nested blocks being parsed.
-    error: The function to call with any errors found.
-  """
-
-  # Don't use "elided" lines here, otherwise we can't check commented lines.
-  # Don't want to use "raw" either, because we don't want to check inside C++11
-  # raw strings,
-  raw_lines = clean_lines.lines_without_raw_strings
-  line = raw_lines[linenum]
-
-  if line.find('\t') != -1:
-    error(filename, linenum, 'whitespace/tab', 1,
-          'Tab found; better to use spaces')
-
-  # One or three blank spaces at the beginning of the line is weird; it's
-  # hard to reconcile that with 2-space indents.
-  # NOTE: here are the conditions rob pike used for his tests.  Mine aren't
-  # as sophisticated, but it may be worth becoming so:  RLENGTH==initial_spaces
-  # if(RLENGTH > 20) complain = 0;
-  # if(match($0, " +(error|private|public|protected):")) complain = 0;
-  # if(match(prev, "&& *$")) complain = 0;
-  # if(match(prev, "\\|\\| *$")) complain = 0;
-  # if(match(prev, "[\",=><] *$")) complain = 0;
-  # if(match($0, " <<")) complain = 0;
-  # if(match(prev, " +for \\(")) complain = 0;
-  # if(prevodd && match(prevprev, " +for \\(")) complain = 0;
-  scope_or_label_pattern = r'\s*\w+\s*:\s*\\?$'
-  classinfo = nesting_state.InnermostClass()
-  initial_spaces = 0
-  cleansed_line = clean_lines.elided[linenum]
-  while initial_spaces < len(line) and line[initial_spaces] == ' ':
-    initial_spaces += 1
-  if line and line[-1].isspace():
-    error(filename, linenum, 'whitespace/end_of_line', 4,
-          'Line ends in whitespace.  Consider deleting these extra spaces.')
-  # There are certain situations we allow one space, notably for
-  # section labels, and also lines containing multi-line raw strings.
-  elif ((initial_spaces == 1 or initial_spaces == 3) and
-        not Match(scope_or_label_pattern, cleansed_line) and
-        not (clean_lines.raw_lines[linenum] != line and
-             Match(r'^\s*""', line))):
-    error(filename, linenum, 'whitespace/indent', 3,
-          'Weird number of spaces at line-start.  '
-          'Are you using a 2-space indent?')
-
-  # Check if the line is a header guard.
-  is_header_guard = False
-  if file_extension == 'h':
-    cppvar = GetHeaderGuardCPPVariable(filename)
-    if (line.startswith('#ifndef %s' % cppvar) or
-        line.startswith('#define %s' % cppvar) or
-        line.startswith('#endif  // %s' % cppvar)):
-      is_header_guard = True
-  # #include lines and header guards can be long, since there's no clean way to
-  # split them.
-  #
-  # URLs can be long too.  It's possible to split these, but it makes them
-  # harder to cut&paste.
-  #
-  # The "$Id:...$" comment may also get very long without it being the
-  # developers fault.
-  if (not line.startswith('#include') and not is_header_guard and
-      not Match(r'^\s*//.*http(s?)://\S*$', line) and
-      not Match(r'^// \$Id:.*#[0-9]+ \$$', line)):
-    line_width = GetLineWidth(line)
-    extended_length = int((_line_length * 1.25))
-    if line_width > extended_length:
-      error(filename, linenum, 'whitespace/line_length', 4,
-            'Lines should very rarely be longer than %i characters' %
-            extended_length)
-    elif line_width > _line_length:
-      error(filename, linenum, 'whitespace/line_length', 2,
-            'Lines should be <= %i characters long' % _line_length)
-
-  if (cleansed_line.count(';') > 1 and
-      # for loops are allowed two ;'s (and may run over two lines).
-      cleansed_line.find('for') == -1 and
-      (GetPreviousNonBlankLine(clean_lines, linenum)[0].find('for') == -1 or
-       GetPreviousNonBlankLine(clean_lines, linenum)[0].find(';') != -1) and
-      # It's ok to have many commands in a switch case that fits in 1 line
-      not ((cleansed_line.find('case ') != -1 or
-            cleansed_line.find('default:') != -1) and
-           cleansed_line.find('break;') != -1)):
-    error(filename, linenum, 'whitespace/newline', 0,
-          'More than one command on the same line')
-
-  # Some more style checks
-  CheckBraces(filename, clean_lines, linenum, error)
-  CheckTrailingSemicolon(filename, clean_lines, linenum, error)
-  CheckEmptyBlockBody(filename, clean_lines, linenum, error)
-  CheckAccess(filename, clean_lines, linenum, nesting_state, error)
-  CheckSpacing(filename, clean_lines, linenum, nesting_state, error)
-  CheckOperatorSpacing(filename, clean_lines, linenum, error)
-  CheckParenthesisSpacing(filename, clean_lines, linenum, error)
-  CheckCommaSpacing(filename, clean_lines, linenum, error)
-  CheckBracesSpacing(filename, clean_lines, linenum, error)
-  CheckSpacingForFunctionCall(filename, clean_lines, linenum, error)
-  CheckRValueReference(filename, clean_lines, linenum, nesting_state, error)
-  CheckCheck(filename, clean_lines, linenum, error)
-  CheckAltTokens(filename, clean_lines, linenum, error)
-  classinfo = nesting_state.InnermostClass()
-  if classinfo:
-    CheckSectionSpacing(filename, clean_lines, classinfo, linenum, error)
-
-
-_RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$')
-# Matches the first component of a filename delimited by -s and _s. That is:
-#  _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo'
-#  _RE_FIRST_COMPONENT.match('foo.cc').group(0) == 'foo'
-#  _RE_FIRST_COMPONENT.match('foo-bar_baz.cc').group(0) == 'foo'
-#  _RE_FIRST_COMPONENT.match('foo_bar-baz.cc').group(0) == 'foo'
-_RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+')
-
-
-def _DropCommonSuffixes(filename):
-  """Drops common suffixes like _test.cc or -inl.h from filename.
-
-  For example:
-    >>> _DropCommonSuffixes('foo/foo-inl.h')
-    'foo/foo'
-    >>> _DropCommonSuffixes('foo/bar/foo.cc')
-    'foo/bar/foo'
-    >>> _DropCommonSuffixes('foo/foo_internal.h')
-    'foo/foo'
-    >>> _DropCommonSuffixes('foo/foo_unusualinternal.h')
-    'foo/foo_unusualinternal'
-
-  Args:
-    filename: The input filename.
-
-  Returns:
-    The filename with the common suffix removed.
-  """
-  for suffix in ('test.cc', 'regtest.cc', 'unittest.cc',
-                 'inl.h', 'impl.h', 'internal.h'):
-    if (filename.endswith(suffix) and len(filename) > len(suffix) and
-        filename[-len(suffix) - 1] in ('-', '_')):
-      return filename[:-len(suffix) - 1]
-  return os.path.splitext(filename)[0]
-
-
-def _IsTestFilename(filename):
-  """Determines if the given filename has a suffix that identifies it as a test.
-
-  Args:
-    filename: The input filename.
-
-  Returns:
-    True if 'filename' looks like a test, False otherwise.
-  """
-  if (filename.endswith('_test.cc') or
-      filename.endswith('_unittest.cc') or
-      filename.endswith('_regtest.cc')):
-    return True
-  else:
-    return False
-
-
-def _ClassifyInclude(fileinfo, include, is_system):
-  """Figures out what kind of header 'include' is.
-
-  Args:
-    fileinfo: The current file cpplint is running over. A FileInfo instance.
-    include: The path to a #included file.
-    is_system: True if the #include used <> rather than "".
-
-  Returns:
-    One of the _XXX_HEADER constants.
-
-  For example:
-    >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'stdio.h', True)
-    _C_SYS_HEADER
-    >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'string', True)
-    _CPP_SYS_HEADER
-    >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/foo.h', False)
-    _LIKELY_MY_HEADER
-    >>> _ClassifyInclude(FileInfo('foo/foo_unknown_extension.cc'),
-    ...                  'bar/foo_other_ext.h', False)
-    _POSSIBLE_MY_HEADER
-    >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/bar.h', False)
-    _OTHER_HEADER
-  """
-  # This is a list of all standard c++ header files, except
-  # those already checked for above.
-  is_cpp_h = include in _CPP_HEADERS
-
-  if is_system:
-    if is_cpp_h:
-      return _CPP_SYS_HEADER
-    else:
-      return _C_SYS_HEADER
-
-  # If the target file and the include we're checking share a
-  # basename when we drop common extensions, and the include
-  # lives in . , then it's likely to be owned by the target file.
-  target_dir, target_base = (
-      os.path.split(_DropCommonSuffixes(fileinfo.RepositoryName())))
-  include_dir, include_base = os.path.split(_DropCommonSuffixes(include))
-  if target_base == include_base and (
-      include_dir == target_dir or
-      include_dir == os.path.normpath(target_dir + '/../public')):
-    return _LIKELY_MY_HEADER
-
-  # If the target and include share some initial basename
-  # component, it's possible the target is implementing the
-  # include, so it's allowed to be first, but we'll never
-  # complain if it's not there.
-  target_first_component = _RE_FIRST_COMPONENT.match(target_base)
-  include_first_component = _RE_FIRST_COMPONENT.match(include_base)
-  if (target_first_component and include_first_component and
-      target_first_component.group(0) ==
-      include_first_component.group(0)):
-    return _POSSIBLE_MY_HEADER
-
-  return _OTHER_HEADER
-
-
-
-def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
-  """Check rules that are applicable to #include lines.
-
-  Strings on #include lines are NOT removed from elided line, to make
-  certain tasks easier. However, to prevent false positives, checks
-  applicable to #include lines in CheckLanguage must be put here.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    include_state: An _IncludeState instance in which the headers are inserted.
-    error: The function to call with any errors found.
-  """
-  fileinfo = FileInfo(filename)
-  line = clean_lines.lines[linenum]
-
-  # "include" should use the new style "foo/bar.h" instead of just "bar.h"
-  # Only do this check if the included header follows google naming
-  # conventions.  If not, assume that it's a 3rd party API that
-  # requires special include conventions.
-  #
-  # We also make an exception for Lua headers, which follow google
-  # naming convention but not the include convention.
-  match = Match(r'#include\s*"([^/]+\.h)"', line)
-  if match and not _THIRD_PARTY_HEADERS_PATTERN.match(match.group(1)):
-    error(filename, linenum, 'build/include', 4,
-          'Include the directory when naming .h files')
-
-  # we shouldn't include a file more than once. actually, there are a
-  # handful of instances where doing so is okay, but in general it's
-  # not.
-  match = _RE_PATTERN_INCLUDE.search(line)
-  if match:
-    include = match.group(2)
-    is_system = (match.group(1) == '<')
-    duplicate_line = include_state.FindHeader(include)
-    if duplicate_line >= 0:
-      error(filename, linenum, 'build/include', 4,
-            '"%s" already included at %s:%s' %
-            (include, filename, duplicate_line))
-    elif (include.endswith('.cc') and
-          os.path.dirname(fileinfo.RepositoryName()) != os.path.dirname(include)):
-      error(filename, linenum, 'build/include', 4,
-            'Do not include .cc files from other packages')
-    elif not _THIRD_PARTY_HEADERS_PATTERN.match(include):
-      include_state.include_list[-1].append((include, linenum))
-
-      # We want to ensure that headers appear in the right order:
-      # 1) for foo.cc, foo.h  (preferred location)
-      # 2) c system files
-      # 3) cpp system files
-      # 4) for foo.cc, foo.h  (deprecated location)
-      # 5) other google headers
-      #
-      # We classify each include statement as one of those 5 types
-      # using a number of techniques. The include_state object keeps
-      # track of the highest type seen, and complains if we see a
-      # lower type after that.
-      error_message = include_state.CheckNextIncludeOrder(
-          _ClassifyInclude(fileinfo, include, is_system))
-      if error_message:
-        error(filename, linenum, 'build/include_order', 4,
-              '%s. Should be: %s.h, c system, c++ system, other.' %
-              (error_message, fileinfo.BaseName()))
-      canonical_include = include_state.CanonicalizeAlphabeticalOrder(include)
-      if not include_state.IsInAlphabeticalOrder(
-          clean_lines, linenum, canonical_include):
-        error(filename, linenum, 'build/include_alpha', 4,
-              'Include "%s" not in alphabetical order' % include)
-      include_state.SetLastHeader(canonical_include)
-
-
-
-def _GetTextInside(text, start_pattern):
-  r"""Retrieves all the text between matching open and close parentheses.
-
-  Given a string of lines and a regular expression string, retrieve all the text
-  following the expression and between opening punctuation symbols like
-  (, [, or {, and the matching close-punctuation symbol. This properly nested
-  occurrences of the punctuations, so for the text like
-    printf(a(), b(c()));
-  a call to _GetTextInside(text, r'printf\(') will return 'a(), b(c())'.
-  start_pattern must match string having an open punctuation symbol at the end.
-
-  Args:
-    text: The lines to extract text. Its comments and strings must be elided.
-           It can be single line and can span multiple lines.
-    start_pattern: The regexp string indicating where to start extracting
-                   the text.
-  Returns:
-    The extracted text.
-    None if either the opening string or ending punctuation could not be found.
-  """
-  # TODO(unknown): Audit cpplint.py to see what places could be profitably
-  # rewritten to use _GetTextInside (and use inferior regexp matching today).
-
-  # Give opening punctuations to get the matching close-punctuations.
-  matching_punctuation = {'(': ')', '{': '}', '[': ']'}
-  closing_punctuation = set(matching_punctuation.itervalues())
-
-  # Find the position to start extracting text.
-  match = re.search(start_pattern, text, re.M)
-  if not match:  # start_pattern not found in text.
-    return None
-  start_position = match.end(0)
-
-  assert start_position > 0, (
-      'start_pattern must ends with an opening punctuation.')
-  assert text[start_position - 1] in matching_punctuation, (
-      'start_pattern must ends with an opening punctuation.')
-  # Stack of closing punctuations we expect to have in text after position.
-  punctuation_stack = [matching_punctuation[text[start_position - 1]]]
-  position = start_position
-  while punctuation_stack and position < len(text):
-    if text[position] == punctuation_stack[-1]:
-      punctuation_stack.pop()
-    elif text[position] in closing_punctuation:
-      # A closing punctuation without matching opening punctuations.
-      return None
-    elif text[position] in matching_punctuation:
-      punctuation_stack.append(matching_punctuation[text[position]])
-    position += 1
-  if punctuation_stack:
-    # Opening punctuations left without matching close-punctuations.
-    return None
-  # punctuations match.
-  return text[start_position:position - 1]
-
-
-# Patterns for matching call-by-reference parameters.
-#
-# Supports nested templates up to 2 levels deep using this messy pattern:
-#   < (?: < (?: < [^<>]*
-#               >
-#           |   [^<>] )*
-#         >
-#     |   [^<>] )*
-#   >
-_RE_PATTERN_IDENT = r'[_a-zA-Z]\w*'  # =~ [[:alpha:]][[:alnum:]]*
-_RE_PATTERN_TYPE = (
-    r'(?:const\s+)?(?:typename\s+|class\s+|struct\s+|union\s+|enum\s+)?'
-    r'(?:\w|'
-    r'\s*<(?:<(?:<[^<>]*>|[^<>])*>|[^<>])*>|'
-    r'::)+')
-# A call-by-reference parameter ends with '& identifier'.
-_RE_PATTERN_REF_PARAM = re.compile(
-    r'(' + _RE_PATTERN_TYPE + r'(?:\s*(?:\bconst\b|[*]))*\s*'
-    r'&\s*' + _RE_PATTERN_IDENT + r')\s*(?:=[^,()]+)?[,)]')
-# A call-by-const-reference parameter either ends with 'const& identifier'
-# or looks like 'const type& identifier' when 'type' is atomic.
-_RE_PATTERN_CONST_REF_PARAM = (
-    r'(?:.*\s*\bconst\s*&\s*' + _RE_PATTERN_IDENT +
-    r'|const\s+' + _RE_PATTERN_TYPE + r'\s*&\s*' + _RE_PATTERN_IDENT + r')')
-
-
-def CheckLanguage(filename, clean_lines, linenum, file_extension,
-                  include_state, nesting_state, error):
-  """Checks rules from the 'C++ language rules' section of cppguide.html.
-
-  Some of these rules are hard to test (function overloading, using
-  uint32 inappropriately), but we do the best we can.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    file_extension: The extension (without the dot) of the filename.
-    include_state: An _IncludeState instance in which the headers are inserted.
-    nesting_state: A NestingState instance which maintains information about
-                   the current stack of nested blocks being parsed.
-    error: The function to call with any errors found.
-  """
-  # If the line is empty or consists of entirely a comment, no need to
-  # check it.
-  line = clean_lines.elided[linenum]
-  if not line:
-    return
-
-  match = _RE_PATTERN_INCLUDE.search(line)
-  if match:
-    CheckIncludeLine(filename, clean_lines, linenum, include_state, error)
-    return
-
-  # Reset include state across preprocessor directives.  This is meant
-  # to silence warnings for conditional includes.
-  match = Match(r'^\s*#\s*(if|ifdef|ifndef|elif|else|endif)\b', line)
-  if match:
-    include_state.ResetSection(match.group(1))
-
-  # Make Windows paths like Unix.
-  fullname = os.path.abspath(filename).replace('\\', '/')
-
-  # Perform other checks now that we are sure that this is not an include line
-  CheckCasts(filename, clean_lines, linenum, error)
-  CheckGlobalStatic(filename, clean_lines, linenum, error)
-  CheckPrintf(filename, clean_lines, linenum, error)
-
-  if file_extension == 'h':
-    # TODO(unknown): check that 1-arg constructors are explicit.
-    #                How to tell it's a constructor?
-    #                (handled in CheckForNonStandardConstructs for now)
-    # TODO(unknown): check that classes declare or disable copy/assign
-    #                (level 1 error)
-    pass
-
-  # Check if people are using the verboten C basic types.  The only exception
-  # we regularly allow is "unsigned short port" for port.
-  if Search(r'\bshort port\b', line):
-    if not Search(r'\bunsigned short port\b', line):
-      error(filename, linenum, 'runtime/int', 4,
-            'Use "unsigned short" for ports, not "short"')
-  else:
-    match = Search(r'\b(short|long(?! +double)|long long)\b', line)
-    if match:
-      error(filename, linenum, 'runtime/int', 4,
-            'Use int16/int64/etc, rather than the C type %s' % match.group(1))
-
-  # Check if some verboten operator overloading is going on
-  # TODO(unknown): catch out-of-line unary operator&:
-  #   class X {};
-  #   int operator&(const X& x) { return 42; }  // unary operator&
-  # The trick is it's hard to tell apart from binary operator&:
-  #   class Y { int operator&(const Y& x) { return 23; } }; // binary operator&
-  if Search(r'\boperator\s*&\s*\(\s*\)', line):
-    error(filename, linenum, 'runtime/operator', 4,
-          'Unary operator& is dangerous.  Do not use it.')
-
-  # Check for suspicious usage of "if" like
-  # } if (a == b) {
-  if Search(r'\}\s*if\s*\(', line):
-    error(filename, linenum, 'readability/braces', 4,
-          'Did you mean "else if"? If not, start a new line for "if".')
-
-  # Check for potential format string bugs like printf(foo).
-  # We constrain the pattern not to pick things like DocidForPrintf(foo).
-  # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str())
-  # TODO(unknown): Catch the following case. Need to change the calling
-  # convention of the whole function to process multiple line to handle it.
-  #   printf(
-  #       boy_this_is_a_really_long_variable_that_cannot_fit_on_the_prev_line);
-  printf_args = _GetTextInside(line, r'(?i)\b(string)?printf\s*\(')
-  if printf_args:
-    match = Match(r'([\w.\->()]+)$', printf_args)
-    if match and match.group(1) != '__VA_ARGS__':
-      function_name = re.search(r'\b((?:string)?printf)\s*\(',
-                                line, re.I).group(1)
-      error(filename, linenum, 'runtime/printf', 4,
-            'Potential format string bug. Do %s("%%s", %s) instead.'
-            % (function_name, match.group(1)))
-
-  # Check for potential memset bugs like memset(buf, sizeof(buf), 0).
-  match = Search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line)
-  if match and not Match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", match.group(2)):
-    error(filename, linenum, 'runtime/memset', 4,
-          'Did you mean "memset(%s, 0, %s)"?'
-          % (match.group(1), match.group(2)))
-
-  if Search(r'\busing namespace\b', line):
-    error(filename, linenum, 'build/namespaces', 5,
-          'Do not use namespace using-directives.  '
-          'Use using-declarations instead.')
-
-  # Detect variable-length arrays.
-  match = Match(r'\s*(.+::)?(\w+) [a-z]\w*\[(.+)];', line)
-  if (match and match.group(2) != 'return' and match.group(2) != 'delete' and
-      match.group(3).find(']') == -1):
-    # Split the size using space and arithmetic operators as delimiters.
-    # If any of the resulting tokens are not compile time constants then
-    # report the error.
-    tokens = re.split(r'\s|\+|\-|\*|\/|<<|>>]', match.group(3))
-    is_const = True
-    skip_next = False
-    for tok in tokens:
-      if skip_next:
-        skip_next = False
-        continue
-
-      if Search(r'sizeof\(.+\)', tok): continue
-      if Search(r'arraysize\(\w+\)', tok): continue
-
-      tok = tok.lstrip('(')
-      tok = tok.rstrip(')')
-      if not tok: continue
-      if Match(r'\d+', tok): continue
-      if Match(r'0[xX][0-9a-fA-F]+', tok): continue
-      if Match(r'k[A-Z0-9]\w*', tok): continue
-      if Match(r'(.+::)?k[A-Z0-9]\w*', tok): continue
-      if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue
-      # A catch all for tricky sizeof cases, including 'sizeof expression',
-      # 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)'
-      # requires skipping the next token because we split on ' ' and '*'.
-      if tok.startswith('sizeof'):
-        skip_next = True
-        continue
-      is_const = False
-      break
-    if not is_const:
-      error(filename, linenum, 'runtime/arrays', 1,
-            'Do not use variable-length arrays.  Use an appropriately named '
-            "('k' followed by CamelCase) compile-time constant for the size.")
-
-  # Check for use of unnamed namespaces in header files.  Registration
-  # macros are typically OK, so we allow use of "namespace {" on lines
-  # that end with backslashes.
-  if (file_extension == 'h'
-      and Search(r'\bnamespace\s*{', line)
-      and line[-1] != '\\'):
-    error(filename, linenum, 'build/namespaces', 4,
-          'Do not use unnamed namespaces in header files.  See '
-          'http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces'
-          ' for more information.')
-
-
-def CheckGlobalStatic(filename, clean_lines, linenum, error):
-  """Check for unsafe global or static objects.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    error: The function to call with any errors found.
-  """
-  line = clean_lines.elided[linenum]
-
-  # Match two lines at a time to support multiline declarations
-  if linenum + 1 < clean_lines.NumLines() and not Search(r'[;({]', line):
-    line += clean_lines.elided[linenum + 1].strip()
-
-  # Check for people declaring static/global STL strings at the top level.
-  # This is dangerous because the C++ language does not guarantee that
-  # globals with constructors are initialized before the first access.
-  match = Match(
-      r'((?:|static +)(?:|const +))string +([a-zA-Z0-9_:]+)\b(.*)',
-      line)
-
-  # Remove false positives:
-  # - String pointers (as opposed to values).
-  #    string *pointer
-  #    const string *pointer
-  #    string const *pointer
-  #    string *const pointer
-  #
-  # - Functions and template specializations.
-  #    string Function<Type>(...
-  #    string Class<Type>::Method(...
-  #
-  # - Operators.  These are matched separately because operator names
-  #   cross non-word boundaries, and trying to match both operators
-  #   and functions at the same time would decrease accuracy of
-  #   matching identifiers.
-  #    string Class::operator*()
-  if (match and
-      not Search(r'\bstring\b(\s+const)?\s*\*\s*(const\s+)?\w', line) and
-      not Search(r'\boperator\W', line) and
-      not Match(r'\s*(<.*>)?(::[a-zA-Z0-9_]+)*\s*\(([^"]|$)', match.group(3))):
-    error(filename, linenum, 'runtime/string', 4,
-          'For a static/global string constant, use a C style string instead: '
-          '"%schar %s[]".' %
-          (match.group(1), match.group(2)))
-
-  if Search(r'\b([A-Za-z0-9_]*_)\(\1\)', line):
-    error(filename, linenum, 'runtime/init', 4,
-          'You seem to be initializing a member variable with itself.')
-
-
-def CheckPrintf(filename, clean_lines, linenum, error):
-  """Check for printf related issues.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    error: The function to call with any errors found.
-  """
-  line = clean_lines.elided[linenum]
-
-  # When snprintf is used, the second argument shouldn't be a literal.
-  match = Search(r'snprintf\s*\(([^,]*),\s*([0-9]*)\s*,', line)
-  if match and match.group(2) != '0':
-    # If 2nd arg is zero, snprintf is used to calculate size.
-    error(filename, linenum, 'runtime/printf', 3,
-          'If you can, use sizeof(%s) instead of %s as the 2nd arg '
-          'to snprintf.' % (match.group(1), match.group(2)))
-
-  # Check if some verboten C functions are being used.
-  if Search(r'\bsprintf\s*\(', line):
-    error(filename, linenum, 'runtime/printf', 5,
-          'Never use sprintf. Use snprintf instead.')
-  match = Search(r'\b(strcpy|strcat)\s*\(', line)
-  if match:
-    error(filename, linenum, 'runtime/printf', 4,
-          'Almost always, snprintf is better than %s' % match.group(1))
-
-
-def IsDerivedFunction(clean_lines, linenum):
-  """Check if current line contains an inherited function.
-
-  Args:
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-  Returns:
-    True if current line contains a function with "override"
-    virt-specifier.
-  """
-  # Scan back a few lines for start of current function
-  for i in xrange(linenum, max(-1, linenum - 10), -1):
-    match = Match(r'^([^()]*\w+)\(', clean_lines.elided[i])
-    if match:
-      # Look for "override" after the matching closing parenthesis
-      line, _, closing_paren = CloseExpression(
-          clean_lines, i, len(match.group(1)))
-      return (closing_paren >= 0 and
-              Search(r'\boverride\b', line[closing_paren:]))
-  return False
-
-
-def IsOutOfLineMethodDefinition(clean_lines, linenum):
-  """Check if current line contains an out-of-line method definition.
-
-  Args:
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-  Returns:
-    True if current line contains an out-of-line method definition.
-  """
-  # Scan back a few lines for start of current function
-  for i in xrange(linenum, max(-1, linenum - 10), -1):
-    if Match(r'^([^()]*\w+)\(', clean_lines.elided[i]):
-      return Match(r'^[^()]*\w+::\w+\(', clean_lines.elided[i]) is not None
-  return False
-
-
-def IsInitializerList(clean_lines, linenum):
-  """Check if current line is inside constructor initializer list.
-
-  Args:
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-  Returns:
-    True if current line appears to be inside constructor initializer
-    list, False otherwise.
-  """
-  for i in xrange(linenum, 1, -1):
-    line = clean_lines.elided[i]
-    if i == linenum:
-      remove_function_body = Match(r'^(.*)\{\s*$', line)
-      if remove_function_body:
-        line = remove_function_body.group(1)
-
-    if Search(r'\s:\s*\w+[({]', line):
-      # A lone colon tend to indicate the start of a constructor
-      # initializer list.  It could also be a ternary operator, which
-      # also tend to appear in constructor initializer lists as
-      # opposed to parameter lists.
-      return True
-    if Search(r'\}\s*,\s*$', line):
-      # A closing brace followed by a comma is probably the end of a
-      # brace-initialized member in constructor initializer list.
-      return True
-    if Search(r'[{};]\s*$', line):
-      # Found one of the following:
-      # - A closing brace or semicolon, probably the end of the previous
-      #   function.
-      # - An opening brace, probably the start of current class or namespace.
-      #
-      # Current line is probably not inside an initializer list since
-      # we saw one of those things without seeing the starting colon.
-      return False
-
-  # Got to the beginning of the file without seeing the start of
-  # constructor initializer list.
-  return False
-
-
-def CheckForNonConstReference(filename, clean_lines, linenum,
-                              nesting_state, error):
-  """Check for non-const references.
-
-  Separate from CheckLanguage since it scans backwards from current
-  line, instead of scanning forward.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    nesting_state: A NestingState instance which maintains information about
-                   the current stack of nested blocks being parsed.
-    error: The function to call with any errors found.
-  """
-  # Do nothing if there is no '&' on current line.
-  line = clean_lines.elided[linenum]
-  if '&' not in line:
-    return
-
-  # If a function is inherited, current function doesn't have much of
-  # a choice, so any non-const references should not be blamed on
-  # derived function.
-  if IsDerivedFunction(clean_lines, linenum):
-    return
-
-  # Don't warn on out-of-line method definitions, as we would warn on the
-  # in-line declaration, if it isn't marked with 'override'.
-  if IsOutOfLineMethodDefinition(clean_lines, linenum):
-    return
-
-  # Long type names may be broken across multiple lines, usually in one
-  # of these forms:
-  #   LongType
-  #       ::LongTypeContinued &identifier
-  #   LongType::
-  #       LongTypeContinued &identifier
-  #   LongType<
-  #       ...>::LongTypeContinued &identifier
-  #
-  # If we detected a type split across two lines, join the previous
-  # line to current line so that we can match const references
-  # accordingly.
-  #
-  # Note that this only scans back one line, since scanning back
-  # arbitrary number of lines would be expensive.  If you have a type
-  # that spans more than 2 lines, please use a typedef.
-  if linenum > 1:
-    previous = None
-    if Match(r'\s*::(?:[\w<>]|::)+\s*&\s*\S', line):
-      # previous_line\n + ::current_line
-      previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+[\w<>])\s*$',
-                        clean_lines.elided[linenum - 1])
-    elif Match(r'\s*[a-zA-Z_]([\w<>]|::)+\s*&\s*\S', line):
-      # previous_line::\n + current_line
-      previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+::)\s*$',
-                        clean_lines.elided[linenum - 1])
-    if previous:
-      line = previous.group(1) + line.lstrip()
-    else:
-      # Check for templated parameter that is split across multiple lines
-      endpos = line.rfind('>')
-      if endpos > -1:
-        (_, startline, startpos) = ReverseCloseExpression(
-            clean_lines, linenum, endpos)
-        if startpos > -1 and startline < linenum:
-          # Found the matching < on an earlier line, collect all
-          # pieces up to current line.
-          line = ''
-          for i in xrange(startline, linenum + 1):
-            line += clean_lines.elided[i].strip()
-
-  # Check for non-const references in function parameters.  A single '&' may
-  # found in the following places:
-  #   inside expression: binary & for bitwise AND
-  #   inside expression: unary & for taking the address of something
-  #   inside declarators: reference parameter
-  # We will exclude the first two cases by checking that we are not inside a
-  # function body, including one that was just introduced by a trailing '{'.
-  # TODO(unknown): Doesn't account for 'catch(Exception& e)' [rare].
-  if (nesting_state.previous_stack_top and
-      not (isinstance(nesting_state.previous_stack_top, _ClassInfo) or
-           isinstance(nesting_state.previous_stack_top, _NamespaceInfo))):
-    # Not at toplevel, not within a class, and not within a namespace
-    return
-
-  # Avoid initializer lists.  We only need to scan back from the
-  # current line for something that starts with ':'.
-  #
-  # We don't need to check the current line, since the '&' would
-  # appear inside the second set of parentheses on the current line as
-  # opposed to the first set.
-  if linenum > 0:
-    for i in xrange(linenum - 1, max(0, linenum - 10), -1):
-      previous_line = clean_lines.elided[i]
-      if not Search(r'[),]\s*$', previous_line):
-        break
-      if Match(r'^\s*:\s+\S', previous_line):
-        return
-
-  # Avoid preprocessors
-  if Search(r'\\\s*$', line):
-    return
-
-  # Avoid constructor initializer lists
-  if IsInitializerList(clean_lines, linenum):
-    return
-
-  # We allow non-const references in a few standard places, like functions
-  # called "swap()" or iostream operators like "<<" or ">>".  Do not check
-  # those function parameters.
-  #
-  # We also accept & in static_assert, which looks like a function but
-  # it's actually a declaration expression.
-  whitelisted_functions = (r'(?:[sS]wap(?:<\w:+>)?|'
-                           r'operator\s*[<>][<>]|'
-                           r'static_assert|COMPILE_ASSERT'
-                           r')\s*\(')
-  if Search(whitelisted_functions, line):
-    return
-  elif not Search(r'\S+\([^)]*$', line):
-    # Don't see a whitelisted function on this line.  Actually we
-    # didn't see any function name on this line, so this is likely a
-    # multi-line parameter list.  Try a bit harder to catch this case.
-    for i in xrange(2):
-      if (linenum > i and
-          Search(whitelisted_functions, clean_lines.elided[linenum - i - 1])):
-        return
-
-  decls = ReplaceAll(r'{[^}]*}', ' ', line)  # exclude function body
-  for parameter in re.findall(_RE_PATTERN_REF_PARAM, decls):
-    if not Match(_RE_PATTERN_CONST_REF_PARAM, parameter):
-      error(filename, linenum, 'runtime/references', 2,
-            'Is this a non-const reference? '
-            'If so, make const or use a pointer: ' +
-            ReplaceAll(' *<', '<', parameter))
-
-
-def CheckCasts(filename, clean_lines, linenum, error):
-  """Various cast related checks.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    error: The function to call with any errors found.
-  """
-  line = clean_lines.elided[linenum]
-
-  # Check to see if they're using an conversion function cast.
-  # I just try to capture the most common basic types, though there are more.
-  # Parameterless conversion functions, such as bool(), are allowed as they are
-  # probably a member operator declaration or default constructor.
-  match = Search(
-      r'(\bnew\s+|\S<\s*(?:const\s+)?)?\b'
-      r'(int|float|double|bool|char|int32|uint32|int64|uint64)'
-      r'(\([^)].*)', line)
-  expecting_function = ExpectingFunctionArgs(clean_lines, linenum)
-  if match and not expecting_function:
-    matched_type = match.group(2)
-
-    # matched_new_or_template is used to silence two false positives:
-    # - New operators
-    # - Template arguments with function types
-    #
-    # For template arguments, we match on types immediately following
-    # an opening bracket without any spaces.  This is a fast way to
-    # silence the common case where the function type is the first
-    # template argument.  False negative with less-than comparison is
-    # avoided because those operators are usually followed by a space.
-    #
-    #   function<double(double)>   // bracket + no space = false positive
-    #   value < double(42)         // bracket + space = true positive
-    matched_new_or_template = match.group(1)
-
-    # Avoid arrays by looking for brackets that come after the closing
-    # parenthesis.
-    if Match(r'\([^()]+\)\s*\[', match.group(3)):
-      return
-
-    # Other things to ignore:
-    # - Function pointers
-    # - Casts to pointer types
-    # - Placement new
-    # - Alias declarations
-    matched_funcptr = match.group(3)
-    if (matched_new_or_template is None and
-        not (matched_funcptr and
-             (Match(r'\((?:[^() ]+::\s*\*\s*)?[^() ]+\)\s*\(',
-                    matched_funcptr) or
-              matched_funcptr.startswith('(*)'))) and
-        not Match(r'\s*using\s+\S+\s*=\s*' + matched_type, line) and
-        not Search(r'new\(\S+\)\s*' + matched_type, line)):
-      error(filename, linenum, 'readability/casting', 4,
-            'Using deprecated casting style.  '
-            'Use static_cast<%s>(...) instead' %
-            matched_type)
-
-  if not expecting_function:
-    CheckCStyleCast(filename, clean_lines, linenum, 'static_cast',
-                    r'\((int|float|double|bool|char|u?int(16|32|64))\)', error)
-
-  # This doesn't catch all cases. Consider (const char * const)"hello".
-  #
-  # (char *) "foo" should always be a const_cast (reinterpret_cast won't
-  # compile).
-  if CheckCStyleCast(filename, clean_lines, linenum, 'const_cast',
-                     r'\((char\s?\*+\s?)\)\s*"', error):
-    pass
-  else:
-    # Check pointer casts for other than string constants
-    CheckCStyleCast(filename, clean_lines, linenum, 'reinterpret_cast',
-                    r'\((\w+\s?\*+\s?)\)', error)
-
-  # In addition, we look for people taking the address of a cast.  This
-  # is dangerous -- casts can assign to temporaries, so the pointer doesn't
-  # point where you think.
-  #
-  # Some non-identifier character is required before the '&' for the
-  # expression to be recognized as a cast.  These are casts:
-  #   expression = &static_cast<int*>(temporary());
-  #   function(&(int*)(temporary()));
-  #
-  # This is not a cast:
-  #   reference_type&(int* function_param);
-  match = Search(
-      r'(?:[^\w]&\(([^)*][^)]*)\)[\w(])|'
-      r'(?:[^\w]&(static|dynamic|down|reinterpret)_cast\b)', line)
-  if match:
-    # Try a better error message when the & is bound to something
-    # dereferenced by the casted pointer, as opposed to the casted
-    # pointer itself.
-    parenthesis_error = False
-    match = Match(r'^(.*&(?:static|dynamic|down|reinterpret)_cast\b)<', line)
-    if match:
-      _, y1, x1 = CloseExpression(clean_lines, linenum, len(match.group(1)))
-      if x1 >= 0 and clean_lines.elided[y1][x1] == '(':
-        _, y2, x2 = CloseExpression(clean_lines, y1, x1)
-        if x2 >= 0:
-          extended_line = clean_lines.elided[y2][x2:]
-          if y2 < clean_lines.NumLines() - 1:
-            extended_line += clean_lines.elided[y2 + 1]
-          if Match(r'\s*(?:->|\[)', extended_line):
-            parenthesis_error = True
-
-    if parenthesis_error:
-      error(filename, linenum, 'readability/casting', 4,
-            ('Are you taking an address of something dereferenced '
-             'from a cast?  Wrapping the dereferenced expression in '
-             'parentheses will make the binding more obvious'))
-    else:
-      error(filename, linenum, 'runtime/casting', 4,
-            ('Are you taking an address of a cast?  '
-             'This is dangerous: could be a temp var.  '
-             'Take the address before doing the cast, rather than after'))
-
-
-def CheckCStyleCast(filename, clean_lines, linenum, cast_type, pattern, error):
-  """Checks for a C-style cast by looking for the pattern.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    cast_type: The string for the C++ cast to recommend.  This is either
-      reinterpret_cast, static_cast, or const_cast, depending.
-    pattern: The regular expression used to find C-style casts.
-    error: The function to call with any errors found.
-
-  Returns:
-    True if an error was emitted.
-    False otherwise.
-  """
-  line = clean_lines.elided[linenum]
-  match = Search(pattern, line)
-  if not match:
-    return False
-
-  # Exclude lines with keywords that tend to look like casts
-  context = line[0:match.start(1) - 1]
-  if Match(r'.*\b(?:sizeof|alignof|alignas|[_A-Z][_A-Z0-9]*)\s*$', context):
-    return False
-
-  # Try expanding current context to see if we one level of
-  # parentheses inside a macro.
-  if linenum > 0:
-    for i in xrange(linenum - 1, max(0, linenum - 5), -1):
-      context = clean_lines.elided[i] + context
-  if Match(r'.*\b[_A-Z][_A-Z0-9]*\s*\((?:\([^()]*\)|[^()])*$', context):
-    return False
-
-  # operator++(int) and operator--(int)
-  if context.endswith(' operator++') or context.endswith(' operator--'):
-    return False
-
-  # A single unnamed argument for a function tends to look like old
-  # style cast.  If we see those, don't issue warnings for deprecated
-  # casts, instead issue warnings for unnamed arguments where
-  # appropriate.
-  #
-  # These are things that we want warnings for, since the style guide
-  # explicitly require all parameters to be named:
-  #   Function(int);
-  #   Function(int) {
-  #   ConstMember(int) const;
-  #   ConstMember(int) const {
-  #   ExceptionMember(int) throw (...);
-  #   ExceptionMember(int) throw (...) {
-  #   PureVirtual(int) = 0;
-  #   [](int) -> bool {
-  #
-  # These are functions of some sort, where the compiler would be fine
-  # if they had named parameters, but people often omit those
-  # identifiers to reduce clutter:
-  #   (FunctionPointer)(int);
-  #   (FunctionPointer)(int) = value;
-  #   Function((function_pointer_arg)(int))
-  #   Function((function_pointer_arg)(int), int param)
-  #   <TemplateArgument(int)>;
-  #   <(FunctionPointerTemplateArgument)(int)>;
-  remainder = line[match.end(0):]
-  if Match(r'^\s*(?:;|const\b|throw\b|final\b|override\b|[=>{),]|->)',
-           remainder):
-    # Looks like an unnamed parameter.
-
-    # Don't warn on any kind of template arguments.
-    if Match(r'^\s*>', remainder):
-      return False
-
-    # Don't warn on assignments to function pointers, but keep warnings for
-    # unnamed parameters to pure virtual functions.  Note that this pattern
-    # will also pass on assignments of "0" to function pointers, but the
-    # preferred values for those would be "nullptr" or "NULL".
-    matched_zero = Match(r'^\s=\s*(\S+)\s*;', remainder)
-    if matched_zero and matched_zero.group(1) != '0':
-      return False
-
-    # Don't warn on function pointer declarations.  For this we need
-    # to check what came before the "(type)" string.
-    if Match(r'.*\)\s*$', line[0:match.start(0)]):
-      return False
-
-    # Don't warn if the parameter is named with block comments, e.g.:
-    #  Function(int /*unused_param*/);
-    raw_line = clean_lines.raw_lines[linenum]
-    if '/*' in raw_line:
-      return False
-
-    # Passed all filters, issue warning here.
-    error(filename, linenum, 'readability/function', 3,
-          'All parameters should be named in a function')
-    return True
-
-  # At this point, all that should be left is actual casts.
-  error(filename, linenum, 'readability/casting', 4,
-        'Using C-style cast.  Use %s<%s>(...) instead' %
-        (cast_type, match.group(1)))
-
-  return True
-
-
-def ExpectingFunctionArgs(clean_lines, linenum):
-  """Checks whether where function type arguments are expected.
-
-  Args:
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-
-  Returns:
-    True if the line at 'linenum' is inside something that expects arguments
-    of function types.
-  """
-  line = clean_lines.elided[linenum]
-  return (Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line) or
-          (linenum >= 2 and
-           (Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\((?:\S+,)?\s*$',
-                  clean_lines.elided[linenum - 1]) or
-            Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\(\s*$',
-                  clean_lines.elided[linenum - 2]) or
-            Search(r'\bstd::m?function\s*\<\s*$',
-                   clean_lines.elided[linenum - 1]))))
-
-
-_HEADERS_CONTAINING_TEMPLATES = (
-    ('<deque>', ('deque',)),
-    ('<functional>', ('unary_function', 'binary_function',
-                      'plus', 'minus', 'multiplies', 'divides', 'modulus',
-                      'negate',
-                      'equal_to', 'not_equal_to', 'greater', 'less',
-                      'greater_equal', 'less_equal',
-                      'logical_and', 'logical_or', 'logical_not',
-                      'unary_negate', 'not1', 'binary_negate', 'not2',
-                      'bind1st', 'bind2nd',
-                      'pointer_to_unary_function',
-                      'pointer_to_binary_function',
-                      'ptr_fun',
-                      'mem_fun_t', 'mem_fun', 'mem_fun1_t', 'mem_fun1_ref_t',
-                      'mem_fun_ref_t',
-                      'const_mem_fun_t', 'const_mem_fun1_t',
-                      'const_mem_fun_ref_t', 'const_mem_fun1_ref_t',
-                      'mem_fun_ref',
-                     )),
-    ('<limits>', ('numeric_limits',)),
-    ('<list>', ('list',)),
-    ('<map>', ('map', 'multimap',)),
-    ('<memory>', ('allocator',)),
-    ('<queue>', ('queue', 'priority_queue',)),
-    ('<set>', ('set', 'multiset',)),
-    ('<stack>', ('stack',)),
-    ('<string>', ('char_traits', 'basic_string',)),
-    ('<tuple>', ('tuple',)),
-    ('<utility>', ('pair',)),
-    ('<vector>', ('vector',)),
-
-    # gcc extensions.
-    # Note: std::hash is their hash, ::hash is our hash
-    ('<hash_map>', ('hash_map', 'hash_multimap',)),
-    ('<hash_set>', ('hash_set', 'hash_multiset',)),
-    ('<slist>', ('slist',)),
-    )
-
-_RE_PATTERN_STRING = re.compile(r'\bstring\b')
-
-_re_pattern_algorithm_header = []
-for _template in ('copy', 'max', 'min', 'min_element', 'sort', 'swap',
-                  'transform'):
-  # Match max<type>(..., ...), max(..., ...), but not foo->max, foo.max or
-  # type::max().
-  _re_pattern_algorithm_header.append(
-      (re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'),
-       _template,
-       '<algorithm>'))
-
-_re_pattern_templates = []
-for _header, _templates in _HEADERS_CONTAINING_TEMPLATES:
-  for _template in _templates:
-    _re_pattern_templates.append(
-        (re.compile(r'(\<|\b)' + _template + r'\s*\<'),
-         _template + '<>',
-         _header))
-
-
-def FilesBelongToSameModule(filename_cc, filename_h):
-  """Check if these two filenames belong to the same module.
-
-  The concept of a 'module' here is a as follows:
-  foo.h, foo-inl.h, foo.cc, foo_test.cc and foo_unittest.cc belong to the
-  same 'module' if they are in the same directory.
-  some/path/public/xyzzy and some/path/internal/xyzzy are also considered
-  to belong to the same module here.
-
-  If the filename_cc contains a longer path than the filename_h, for example,
-  '/absolute/path/to/base/sysinfo.cc', and this file would include
-  'base/sysinfo.h', this function also produces the prefix needed to open the
-  header. This is used by the caller of this function to more robustly open the
-  header file. We don't have access to the real include paths in this context,
-  so we need this guesswork here.
-
-  Known bugs: tools/base/bar.cc and base/bar.h belong to the same module
-  according to this implementation. Because of this, this function gives
-  some false positives. This should be sufficiently rare in practice.
-
-  Args:
-    filename_cc: is the path for the .cc file
-    filename_h: is the path for the header path
-
-  Returns:
-    Tuple with a bool and a string:
-    bool: True if filename_cc and filename_h belong to the same module.
-    string: the additional prefix needed to open the header file.
-  """
-
-  if not filename_cc.endswith('.cc'):
-    return (False, '')
-  filename_cc = filename_cc[:-len('.cc')]
-  if filename_cc.endswith('_unittest'):
-    filename_cc = filename_cc[:-len('_unittest')]
-  elif filename_cc.endswith('_test'):
-    filename_cc = filename_cc[:-len('_test')]
-  filename_cc = filename_cc.replace('/public/', '/')
-  filename_cc = filename_cc.replace('/internal/', '/')
-
-  if not filename_h.endswith('.h'):
-    return (False, '')
-  filename_h = filename_h[:-len('.h')]
-  if filename_h.endswith('-inl'):
-    filename_h = filename_h[:-len('-inl')]
-  filename_h = filename_h.replace('/public/', '/')
-  filename_h = filename_h.replace('/internal/', '/')
-
-  files_belong_to_same_module = filename_cc.endswith(filename_h)
-  common_path = ''
-  if files_belong_to_same_module:
-    common_path = filename_cc[:-len(filename_h)]
-  return files_belong_to_same_module, common_path
-
-
-def UpdateIncludeState(filename, include_dict, io=codecs):
-  """Fill up the include_dict with new includes found from the file.
-
-  Args:
-    filename: the name of the header to read.
-    include_dict: a dictionary in which the headers are inserted.
-    io: The io factory to use to read the file. Provided for testability.
-
-  Returns:
-    True if a header was successfully added. False otherwise.
-  """
-  headerfile = None
-  try:
-    headerfile = io.open(filename, 'r', 'utf8', 'replace')
-  except IOError:
-    return False
-  linenum = 0
-  for line in headerfile:
-    linenum += 1
-    clean_line = CleanseComments(line)
-    match = _RE_PATTERN_INCLUDE.search(clean_line)
-    if match:
-      include = match.group(2)
-      include_dict.setdefault(include, linenum)
-  return True
-
-
-def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
-                              io=codecs):
-  """Reports for missing stl includes.
-
-  This function will output warnings to make sure you are including the headers
-  necessary for the stl containers and functions that you use. We only give one
-  reason to include a header. For example, if you use both equal_to<> and
-  less<> in a .h file, only one (the latter in the file) of these will be
-  reported as a reason to include the <functional>.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    include_state: An _IncludeState instance.
-    error: The function to call with any errors found.
-    io: The IO factory to use to read the header file. Provided for unittest
-        injection.
-  """
-  required = {}  # A map of header name to linenumber and the template entity.
-                 # Example of required: { '<functional>': (1219, 'less<>') }
-
-  for linenum in xrange(clean_lines.NumLines()):
-    line = clean_lines.elided[linenum]
-    if not line or line[0] == '#':
-      continue
-
-    # String is special -- it is a non-templatized type in STL.
-    matched = _RE_PATTERN_STRING.search(line)
-    if matched:
-      # Don't warn about strings in non-STL namespaces:
-      # (We check only the first match per line; good enough.)
-      prefix = line[:matched.start()]
-      if prefix.endswith('std::') or not prefix.endswith('::'):
-        required['<string>'] = (linenum, 'string')
-
-    for pattern, template, header in _re_pattern_algorithm_header:
-      if pattern.search(line):
-        required[header] = (linenum, template)
-
-    # The following function is just a speed up, no semantics are changed.
-    if not '<' in line:  # Reduces the cpu time usage by skipping lines.
-      continue
-
-    for pattern, template, header in _re_pattern_templates:
-      if pattern.search(line):
-        required[header] = (linenum, template)
-
-  # The policy is that if you #include something in foo.h you don't need to
-  # include it again in foo.cc. Here, we will look at possible includes.
-  # Let's flatten the include_state include_list and copy it into a dictionary.
-  include_dict = dict([item for sublist in include_state.include_list
-                       for item in sublist])
-
-  # Did we find the header for this file (if any) and successfully load it?
-  header_found = False
-
-  # Use the absolute path so that matching works properly.
-  abs_filename = FileInfo(filename).FullName()
-
-  # For Emacs's flymake.
-  # If cpplint is invoked from Emacs's flymake, a temporary file is generated
-  # by flymake and that file name might end with '_flymake.cc'. In that case,
-  # restore original file name here so that the corresponding header file can be
-  # found.
-  # e.g. If the file name is 'foo_flymake.cc', we should search for 'foo.h'
-  # instead of 'foo_flymake.h'
-  abs_filename = re.sub(r'_flymake\.cc$', '.cc', abs_filename)
-
-  # include_dict is modified during iteration, so we iterate over a copy of
-  # the keys.
-  header_keys = include_dict.keys()
-  for header in header_keys:
-    (same_module, common_path) = FilesBelongToSameModule(abs_filename, header)
-    fullpath = common_path + header
-    if same_module and UpdateIncludeState(fullpath, include_dict, io):
-      header_found = True
-
-  # If we can't find the header file for a .cc, assume it's because we don't
-  # know where to look. In that case we'll give up as we're not sure they
-  # didn't include it in the .h file.
-  # TODO(unknown): Do a better job of finding .h files so we are confident that
-  # not having the .h file means there isn't one.
-  if filename.endswith('.cc') and not header_found:
-    return
-
-  # All the lines have been processed, report the errors found.
-  for required_header_unstripped in required:
-    template = required[required_header_unstripped][1]
-    if required_header_unstripped.strip('<>"') not in include_dict:
-      error(filename, required[required_header_unstripped][0],
-            'build/include_what_you_use', 4,
-            'Add #include ' + required_header_unstripped + ' for ' + template)
-
-
-_RE_PATTERN_EXPLICIT_MAKEPAIR = re.compile(r'\bmake_pair\s*<')
-
-
-def CheckMakePairUsesDeduction(filename, clean_lines, linenum, error):
-  """Check that make_pair's template arguments are deduced.
-
-  G++ 4.6 in C++11 mode fails badly if make_pair's template arguments are
-  specified explicitly, and such use isn't intended in any case.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    error: The function to call with any errors found.
-  """
-  line = clean_lines.elided[linenum]
-  match = _RE_PATTERN_EXPLICIT_MAKEPAIR.search(line)
-  if match:
-    error(filename, linenum, 'build/explicit_make_pair',
-          4,  # 4 = high confidence
-          'For C++11-compatibility, omit template arguments from make_pair'
-          ' OR use pair directly OR if appropriate, construct a pair directly')
-
-
-def CheckDefaultLambdaCaptures(filename, clean_lines, linenum, error):
-  """Check that default lambda captures are not used.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    error: The function to call with any errors found.
-  """
-  line = clean_lines.elided[linenum]
-
-  # A lambda introducer specifies a default capture if it starts with "[="
-  # or if it starts with "[&" _not_ followed by an identifier.
-  match = Match(r'^(.*)\[\s*(?:=|&[^\w])', line)
-  if match:
-    # Found a potential error, check what comes after the lambda-introducer.
-    # If it's not open parenthesis (for lambda-declarator) or open brace
-    # (for compound-statement), it's not a lambda.
-    line, _, pos = CloseExpression(clean_lines, linenum, len(match.group(1)))
-    if pos >= 0 and Match(r'^\s*[{(]', line[pos:]):
-      error(filename, linenum, 'build/c++11',
-            4,  # 4 = high confidence
-            'Default lambda captures are an unapproved C++ feature.')
-
-
-def CheckRedundantVirtual(filename, clean_lines, linenum, error):
-  """Check if line contains a redundant "virtual" function-specifier.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    error: The function to call with any errors found.
-  """
-  # Look for "virtual" on current line.
-  line = clean_lines.elided[linenum]
-  virtual = Match(r'^(.*)(\bvirtual\b)(.*)$', line)
-  if not virtual: return
-
-  # Ignore "virtual" keywords that are near access-specifiers.  These
-  # are only used in class base-specifier and do not apply to member
-  # functions.
-  if (Search(r'\b(public|protected|private)\s+$', virtual.group(1)) or
-      Match(r'^\s+(public|protected|private)\b', virtual.group(3))):
-    return
-
-  # Ignore the "virtual" keyword from virtual base classes.  Usually
-  # there is a column on the same line in these cases (virtual base
-  # classes are rare in google3 because multiple inheritance is rare).
-  if Match(r'^.*[^:]:[^:].*$', line): return
-
-  # Look for the next opening parenthesis.  This is the start of the
-  # parameter list (possibly on the next line shortly after virtual).
-  # TODO(unknown): doesn't work if there are virtual functions with
-  # decltype() or other things that use parentheses, but csearch suggests
-  # that this is rare.
-  end_col = -1
-  end_line = -1
-  start_col = len(virtual.group(2))
-  for start_line in xrange(linenum, min(linenum + 3, clean_lines.NumLines())):
-    line = clean_lines.elided[start_line][start_col:]
-    parameter_list = Match(r'^([^(]*)\(', line)
-    if parameter_list:
-      # Match parentheses to find the end of the parameter list
-      (_, end_line, end_col) = CloseExpression(
-          clean_lines, start_line, start_col + len(parameter_list.group(1)))
-      break
-    start_col = 0
-
-  if end_col < 0:
-    return  # Couldn't find end of parameter list, give up
-
-  # Look for "override" or "final" after the parameter list
-  # (possibly on the next few lines).
-  for i in xrange(end_line, min(end_line + 3, clean_lines.NumLines())):
-    line = clean_lines.elided[i][end_col:]
-    match = Search(r'\b(override|final)\b', line)
-    if match:
-      error(filename, linenum, 'readability/inheritance', 4,
-            ('"virtual" is redundant since function is '
-             'already declared as "%s"' % match.group(1)))
-
-    # Set end_col to check whole lines after we are done with the
-    # first line.
-    end_col = 0
-    if Search(r'[^\w]\s*$', line):
-      break
-
-
-def CheckRedundantOverrideOrFinal(filename, clean_lines, linenum, error):
-  """Check if line contains a redundant "override" or "final" virt-specifier.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    error: The function to call with any errors found.
-  """
-  # Look for closing parenthesis nearby.  We need one to confirm where
-  # the declarator ends and where the virt-specifier starts to avoid
-  # false positives.
-  line = clean_lines.elided[linenum]
-  declarator_end = line.rfind(')')
-  if declarator_end >= 0:
-    fragment = line[declarator_end:]
-  else:
-    if linenum > 1 and clean_lines.elided[linenum - 1].rfind(')') >= 0:
-      fragment = line
-    else:
-      return
-
-  # Check that at most one of "override" or "final" is present, not both
-  if Search(r'\boverride\b', fragment) and Search(r'\bfinal\b', fragment):
-    error(filename, linenum, 'readability/inheritance', 4,
-          ('"override" is redundant since function is '
-           'already declared as "final"'))
-
-
-
-
-# Returns true if we are at a new block, and it is directly
-# inside of a namespace.
-def IsBlockInNameSpace(nesting_state, is_forward_declaration):
-  """Checks that the new block is directly in a namespace.
-
-  Args:
-    nesting_state: The _NestingState object that contains info about our state.
-    is_forward_declaration: If the class is a forward declared class.
-  Returns:
-    Whether or not the new block is directly in a namespace.
-  """
-  if is_forward_declaration:
-    if len(nesting_state.stack) >= 1 and (
-        isinstance(nesting_state.stack[-1], _NamespaceInfo)):
-      return True
-    else:
-      return False
-
-  return (len(nesting_state.stack) > 1 and
-          nesting_state.stack[-1].check_namespace_indentation and
-          isinstance(nesting_state.stack[-2], _NamespaceInfo))
-
-
-def ShouldCheckNamespaceIndentation(nesting_state, is_namespace_indent_item,
-                                    raw_lines_no_comments, linenum):
-  """This method determines if we should apply our namespace indentation check.
-
-  Args:
-    nesting_state: The current nesting state.
-    is_namespace_indent_item: If we just put a new class on the stack, True.
-      If the top of the stack is not a class, or we did not recently
-      add the class, False.
-    raw_lines_no_comments: The lines without the comments.
-    linenum: The current line number we are processing.
-
-  Returns:
-    True if we should apply our namespace indentation check. Currently, it
-    only works for classes and namespaces inside of a namespace.
-  """
-
-  is_forward_declaration = IsForwardClassDeclaration(raw_lines_no_comments,
-                                                     linenum)
-
-  if not (is_namespace_indent_item or is_forward_declaration):
-    return False
-
-  # If we are in a macro, we do not want to check the namespace indentation.
-  if IsMacroDefinition(raw_lines_no_comments, linenum):
-    return False
-
-  return IsBlockInNameSpace(nesting_state, is_forward_declaration)
-
-
-# Call this method if the line is directly inside of a namespace.
-# If the line above is blank (excluding comments) or the start of
-# an inner namespace, it cannot be indented.
-def CheckItemIndentationInNamespace(filename, raw_lines_no_comments, linenum,
-                                    error):
-  line = raw_lines_no_comments[linenum]
-  if Match(r'^\s+', line):
-    error(filename, linenum, 'runtime/indentation_namespace', 4,
-          'Do not indent within a namespace')
-
-
-def ProcessLine(filename, file_extension, clean_lines, line,
-                include_state, function_state, nesting_state, error,
-                extra_check_functions=[]):
-  """Processes a single line in the file.
-
-  Args:
-    filename: Filename of the file that is being processed.
-    file_extension: The extension (dot not included) of the file.
-    clean_lines: An array of strings, each representing a line of the file,
-                 with comments stripped.
-    line: Number of line being processed.
-    include_state: An _IncludeState instance in which the headers are inserted.
-    function_state: A _FunctionState instance which counts function lines, etc.
-    nesting_state: A NestingState instance which maintains information about
-                   the current stack of nested blocks being parsed.
-    error: A callable to which errors are reported, which takes 4 arguments:
-           filename, line number, error level, and message
-    extra_check_functions: An array of additional check functions that will be
-                           run on each source line. Each function takes 4
-                           arguments: filename, clean_lines, line, error
-  """
-  raw_lines = clean_lines.raw_lines
-  ParseNolintSuppressions(filename, raw_lines[line], line, error)
-  nesting_state.Update(filename, clean_lines, line, error)
-  CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line,
-                               error)
-  if nesting_state.InAsmBlock(): return
-  CheckForFunctionLengths(filename, clean_lines, line, function_state, error)
-  CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error)
-  CheckStyle(filename, clean_lines, line, file_extension, nesting_state, error)
-  CheckLanguage(filename, clean_lines, line, file_extension, include_state,
-                nesting_state, error)
-  CheckForNonConstReference(filename, clean_lines, line, nesting_state, error)
-  CheckForNonStandardConstructs(filename, clean_lines, line,
-                                nesting_state, error)
-  CheckVlogArguments(filename, clean_lines, line, error)
-  CheckPosixThreading(filename, clean_lines, line, error)
-  CheckInvalidIncrement(filename, clean_lines, line, error)
-  CheckMakePairUsesDeduction(filename, clean_lines, line, error)
-  CheckDefaultLambdaCaptures(filename, clean_lines, line, error)
-  CheckRedundantVirtual(filename, clean_lines, line, error)
-  CheckRedundantOverrideOrFinal(filename, clean_lines, line, error)
-  for check_fn in extra_check_functions:
-    check_fn(filename, clean_lines, line, error)
-
-def FlagCxx11Features(filename, clean_lines, linenum, error):
-  """Flag those c++11 features that we only allow in certain places.
-
-  Args:
-    filename: The name of the current file.
-    clean_lines: A CleansedLines instance containing the file.
-    linenum: The number of the line to check.
-    error: The function to call with any errors found.
-  """
-  line = clean_lines.elided[linenum]
-
-  # Flag unapproved C++11 headers.
-  include = Match(r'\s*#\s*include\s+[<"]([^<"]+)[">]', line)
-  if include and include.group(1) in ('cfenv',
-                                      'condition_variable',
-                                      'fenv.h',
-                                      'future',
-                                      'mutex',
-                                      'thread',
-                                      'chrono',
-                                      'ratio',
-                                      'regex',
-                                      'system_error',
-                                     ):
-    error(filename, linenum, 'build/c++11', 5,
-          ('<%s> is an unapproved C++11 header.') % include.group(1))
-
-  # The only place where we need to worry about C++11 keywords and library
-  # features in preprocessor directives is in macro definitions.
-  if Match(r'\s*#', line) and not Match(r'\s*#\s*define\b', line): return
-
-  # These are classes and free functions.  The classes are always
-  # mentioned as std::*, but we only catch the free functions if
-  # they're not found by ADL.  They're alphabetical by header.
-  for top_name in (
-      # type_traits
-      'alignment_of',
-      'aligned_union',
-      ):
-    if Search(r'\bstd::%s\b' % top_name, line):
-      error(filename, linenum, 'build/c++11', 5,
-            ('std::%s is an unapproved C++11 class or function.  Send c-style '
-             'an example of where it would make your code more readable, and '
-             'they may let you use it.') % top_name)
-
-
-def ProcessFileData(filename, file_extension, lines, error,
-                    extra_check_functions=[]):
-  """Performs lint checks and reports any errors to the given error function.
-
-  Args:
-    filename: Filename of the file that is being processed.
-    file_extension: The extension (dot not included) of the file.
-    lines: An array of strings, each representing a line of the file, with the
-           last element being empty if the file is terminated with a newline.
-    error: A callable to which errors are reported, which takes 4 arguments:
-           filename, line number, error level, and message
-    extra_check_functions: An array of additional check functions that will be
-                           run on each source line. Each function takes 4
-                           arguments: filename, clean_lines, line, error
-  """
-  lines = (['// marker so line numbers and indices both start at 1'] + lines +
-           ['// marker so line numbers end in a known way'])
-
-  include_state = _IncludeState()
-  function_state = _FunctionState()
-  nesting_state = NestingState()
-
-  ResetNolintSuppressions()
-
-  CheckForCopyright(filename, lines, error)
-
-  RemoveMultiLineComments(filename, lines, error)
-  clean_lines = CleansedLines(lines)
-
-  if file_extension == 'h':
-    CheckForHeaderGuard(filename, clean_lines, error)
-
-  for line in xrange(clean_lines.NumLines()):
-    ProcessLine(filename, file_extension, clean_lines, line,
-                include_state, function_state, nesting_state, error,
-                extra_check_functions)
-    FlagCxx11Features(filename, clean_lines, line, error)
-  nesting_state.CheckCompletedBlocks(filename, error)
-
-  CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error)
-
-  # Check that the .cc file has included its header if it exists.
-  if file_extension == 'cc':
-    CheckHeaderFileIncluded(filename, include_state, error)
-
-  # We check here rather than inside ProcessLine so that we see raw
-  # lines rather than "cleaned" lines.
-  CheckForBadCharacters(filename, lines, error)
-
-  CheckForNewlineAtEOF(filename, lines, error)
-
-def ProcessConfigOverrides(filename):
-  """ Loads the configuration files and processes the config overrides.
-
-  Args:
-    filename: The name of the file being processed by the linter.
-
-  Returns:
-    False if the current |filename| should not be processed further.
-  """
-
-  abs_filename = os.path.abspath(filename)
-  cfg_filters = []
-  keep_looking = True
-  while keep_looking:
-    abs_path, base_name = os.path.split(abs_filename)
-    if not base_name:
-      break  # Reached the root directory.
-
-    cfg_file = os.path.join(abs_path, "CPPLINT.cfg")
-    abs_filename = abs_path
-    if not os.path.isfile(cfg_file):
-      continue
-
-    try:
-      with open(cfg_file) as file_handle:
-        for line in file_handle:
-          line, _, _ = line.partition('#')  # Remove comments.
-          if not line.strip():
-            continue
-
-          name, _, val = line.partition('=')
-          name = name.strip()
-          val = val.strip()
-          if name == 'set noparent':
-            keep_looking = False
-          elif name == 'filter':
-            cfg_filters.append(val)
-          elif name == 'exclude_files':
-            # When matching exclude_files pattern, use the base_name of
-            # the current file name or the directory name we are processing.
-            # For example, if we are checking for lint errors in /foo/bar/baz.cc
-            # and we found the .cfg file at /foo/CPPLINT.cfg, then the config
-            # file's "exclude_files" filter is meant to be checked against "bar"
-            # and not "baz" nor "bar/baz.cc".
-            if base_name:
-              pattern = re.compile(val)
-              if pattern.match(base_name):
-                sys.stderr.write('Ignoring "%s": file excluded by "%s". '
-                                 'File path component "%s" matches '
-                                 'pattern "%s"\n' %
-                                 (filename, cfg_file, base_name, val))
-                return False
-          elif name == 'linelength':
-            global _line_length
-            try:
-                _line_length = int(val)
-            except ValueError:
-                sys.stderr.write('Line length must be numeric.')
-          else:
-            sys.stderr.write(
-                'Invalid configuration option (%s) in file %s\n' %
-                (name, cfg_file))
-
-    except IOError:
-      sys.stderr.write(
-          "Skipping config file '%s': Can't open for reading\n" % cfg_file)
-      keep_looking = False
-
-  # Apply all the accumulated filters in reverse order (top-level directory
-  # config options having the least priority).
-  for filter in reversed(cfg_filters):
-     _AddFilters(filter)
-
-  return True
-
-
-def ProcessFile(filename, vlevel, extra_check_functions=[]):
-  """Does google-lint on a single file.
-
-  Args:
-    filename: The name of the file to parse.
-
-    vlevel: The level of errors to report.  Every error of confidence
-    >= verbose_level will be reported.  0 is a good default.
-
-    extra_check_functions: An array of additional check functions that will be
-                           run on each source line. Each function takes 4
-                           arguments: filename, clean_lines, line, error
-  """
-
-  _SetVerboseLevel(vlevel)
-  _BackupFilters()
-
-  if not ProcessConfigOverrides(filename):
-    _RestoreFilters()
-    return
-
-  lf_lines = []
-  crlf_lines = []
-  try:
-    # Support the UNIX convention of using "-" for stdin.  Note that
-    # we are not opening the file with universal newline support
-    # (which codecs doesn't support anyway), so the resulting lines do
-    # contain trailing '\r' characters if we are reading a file that
-    # has CRLF endings.
-    # If after the split a trailing '\r' is present, it is removed
-    # below.
-    if filename == '-':
-      lines = codecs.StreamReaderWriter(sys.stdin,
-                                        codecs.getreader('utf8'),
-                                        codecs.getwriter('utf8'),
-                                        'replace').read().split('\n')
-    else:
-      lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n')
-
-    # Remove trailing '\r'.
-    # The -1 accounts for the extra trailing blank line we get from split()
-    for linenum in range(len(lines) - 1):
-      if lines[linenum].endswith('\r'):
-        lines[linenum] = lines[linenum].rstrip('\r')
-        crlf_lines.append(linenum + 1)
-      else:
-        lf_lines.append(linenum + 1)
-
-  except IOError:
-    sys.stderr.write(
-        "Skipping input '%s': Can't open for reading\n" % filename)
-    _RestoreFilters()
-    return
-
-  # Note, if no dot is found, this will give the entire filename as the ext.
-  file_extension = filename[filename.rfind('.') + 1:]
-
-  # When reading from stdin, the extension is unknown, so no cpplint tests
-  # should rely on the extension.
-  if filename != '-' and file_extension not in _valid_extensions:
-    sys.stderr.write('Ignoring %s; not a valid file name '
-                     '(%s)\n' % (filename, ', '.join(_valid_extensions)))
-  else:
-    ProcessFileData(filename, file_extension, lines, Error,
-                    extra_check_functions)
-
-    # If end-of-line sequences are a mix of LF and CR-LF, issue
-    # warnings on the lines with CR.
-    #
-    # Don't issue any warnings if all lines are uniformly LF or CR-LF,
-    # since critique can handle these just fine, and the style guide
-    # doesn't dictate a particular end of line sequence.
-    #
-    # We can't depend on os.linesep to determine what the desired
-    # end-of-line sequence should be, since that will return the
-    # server-side end-of-line sequence.
-    if lf_lines and crlf_lines:
-      # Warn on every line with CR.  An alternative approach might be to
-      # check whether the file is mostly CRLF or just LF, and warn on the
-      # minority, we bias toward LF here since most tools prefer LF.
-      for linenum in crlf_lines:
-        Error(filename, linenum, 'whitespace/newline', 1,
-              'Unexpected \\r (^M) found; better to use only \\n')
-
-  sys.stderr.write('Done processing %s\n' % filename)
-  _RestoreFilters()
-
-
-def PrintUsage(message):
-  """Prints a brief usage string and exits, optionally with an error message.
-
-  Args:
-    message: The optional error message.
-  """
-  sys.stderr.write(_USAGE)
-  if message:
-    sys.exit('\nFATAL ERROR: ' + message)
-  else:
-    sys.exit(1)
-
-
-def PrintCategories():
-  """Prints a list of all the error-categories used by error messages.
-
-  These are the categories used to filter messages via --filter.
-  """
-  sys.stderr.write(''.join('  %s\n' % cat for cat in _ERROR_CATEGORIES))
-  sys.exit(0)
-
-
-def ParseArguments(args):
-  """Parses the command line arguments.
-
-  This may set the output format and verbosity level as side-effects.
-
-  Args:
-    args: The command line arguments:
-
-  Returns:
-    The list of filenames to lint.
-  """
-  try:
-    (opts, filenames) = getopt.getopt(args, '', ['help', 'output=', 'verbose=',
-                                                 'counting=',
-                                                 'filter=',
-                                                 'root=',
-                                                 'linelength=',
-                                                 'extensions='])
-  except getopt.GetoptError:
-    PrintUsage('Invalid arguments.')
-
-  verbosity = _VerboseLevel()
-  output_format = _OutputFormat()
-  filters = ''
-  counting_style = ''
-
-  for (opt, val) in opts:
-    if opt == '--help':
-      PrintUsage(None)
-    elif opt == '--output':
-      if val not in ('emacs', 'vs7', 'eclipse'):
-        PrintUsage('The only allowed output formats are emacs, vs7 and eclipse.')
-      output_format = val
-    elif opt == '--verbose':
-      verbosity = int(val)
-    elif opt == '--filter':
-      filters = val
-      if not filters:
-        PrintCategories()
-    elif opt == '--counting':
-      if val not in ('total', 'toplevel', 'detailed'):
-        PrintUsage('Valid counting options are total, toplevel, and detailed')
-      counting_style = val
-    elif opt == '--root':
-      global _root
-      _root = val
-    elif opt == '--linelength':
-      global _line_length
-      try:
-          _line_length = int(val)
-      except ValueError:
-          PrintUsage('Line length must be digits.')
-    elif opt == '--extensions':
-      global _valid_extensions
-      try:
-          _valid_extensions = set(val.split(','))
-      except ValueError:
-          PrintUsage('Extensions must be comma seperated list.')
-
-  if not filenames:
-    PrintUsage('No files were specified.')
-
-  _SetOutputFormat(output_format)
-  _SetVerboseLevel(verbosity)
-  _SetFilters(filters)
-  _SetCountingStyle(counting_style)
-
-  return filenames
-
-
-def main():
-  filenames = ParseArguments(sys.argv[1:])
-
-  # Change stderr to write with replacement characters so we don't die
-  # if we try to print something containing non-ASCII characters.
-  sys.stderr = codecs.StreamReaderWriter(sys.stderr,
-                                         codecs.getreader('utf8'),
-                                         codecs.getwriter('utf8'),
-                                         'replace')
-
-  _cpplint_state.ResetErrorCounts()
-  for filename in filenames:
-    ProcessFile(filename, _cpplint_state.verbose_level)
-  _cpplint_state.PrintErrorCounts()
-
-  sys.exit(_cpplint_state.error_count > 0)
-
-
-if __name__ == '__main__':
-  main()
diff --git a/build-support/run-clang-format.sh b/build-support/run-clang-format.sh
deleted file mode 100755
index 01ddab2..0000000
--- a/build-support/run-clang-format.sh
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/bin/bash
-#
-# 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.
-#
-# Runs clang format in the given directory
-# Arguments:
-#   $1 - Path to the source tree
-#   $2 - Path to the clang format binary
-#   $3 - Apply fixes (will raise an error if false and not there where changes)
-#   $ARGN - Files to run clang format on
-#
-SOURCE_DIR=$1
-shift
-CLANG_FORMAT=$1
-shift
-APPLY_FIXES=$1
-shift
-
-# clang format will only find its configuration if we are in
-# the source tree or in a path relative to the source tree
-pushd $SOURCE_DIR
-if [ "$APPLY_FIXES" == "1" ]; then
-  $CLANG_FORMAT -i $@
-else
-
-  NUM_CORRECTIONS=`$CLANG_FORMAT -output-replacements-xml  $@ | grep offset | wc -l`
-  if [ "$NUM_CORRECTIONS" -gt "0" ]; then
-    echo "clang-format suggested changes, please run 'make format'!!!!"
-    exit 1
-  fi
-fi
-popd
diff --git a/build-support/run-clang-tidy.sh b/build-support/run-clang-tidy.sh
deleted file mode 100755
index 2a4b1c0..0000000
--- a/build-support/run-clang-tidy.sh
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/bin/bash
-#
-# 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.
-#
-#
-# Runs clang format in the given directory
-# Arguments:
-#   $1 - Path to the clang tidy binary
-#   $2 - Path to the compile_commands.json to use
-#   $3 - Apply fixes (will raise an error if false and not there where changes)
-#   $ARGN - Files to run clang-tidy on
-#
-CLANG_TIDY=$1
-shift
-COMPILE_COMMANDS=$1
-shift
-APPLY_FIXES=$1
-shift
-
-# clang format will only find its configuration if we are in
-# the source tree or in a path relative to the source tree
-if [ "$APPLY_FIXES" == "1" ]; then
-  $CLANG_TIDY -p $COMPILE_COMMANDS -fix  $@
-else
-  NUM_CORRECTIONS=`$CLANG_TIDY -p $COMPILE_COMMANDS $@ 2>&1 | grep -v Skipping | grep "warnings* generated" | wc -l`
-  if [ "$NUM_CORRECTIONS" -gt "0" ]; then
-    echo "clang-tidy had suggested fixes.  Please fix these!!!"
-    exit 1
-  fi
-fi
diff --git a/build-support/run-test.sh b/build-support/run-test.sh
deleted file mode 100755
index 7c3d8f6..0000000
--- a/build-support/run-test.sh
+++ /dev/null
@@ -1,229 +0,0 @@
-#!/bin/bash
-#
-# 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.
-#
-# Script which wraps running a test and redirects its output to a
-# test log directory.
-#
-# Arguments:
-#    $1 - Base path for logs/artifacts.
-#    $2 - type of test (e.g. test or benchmark)
-#    $3 - path to executable
-#    $ARGN - arguments for executable
-#
-
-OUTPUT_ROOT=$1
-shift
-ROOT=$(cd $(dirname $BASH_SOURCE)/..; pwd)
-
-TEST_LOGDIR=$OUTPUT_ROOT/build/$1-logs
-mkdir -p $TEST_LOGDIR
-
-RUN_TYPE=$1
-shift
-TEST_DEBUGDIR=$OUTPUT_ROOT/build/$RUN_TYPE-debug
-mkdir -p $TEST_DEBUGDIR
-
-TEST_DIRNAME=$(cd $(dirname $1); pwd)
-TEST_FILENAME=$(basename $1)
-shift
-TEST_EXECUTABLE="$TEST_DIRNAME/$TEST_FILENAME"
-TEST_NAME=$(echo $TEST_FILENAME | perl -pe 's/\..+?$//') # Remove path and extension (if any).
-
-# We run each test in its own subdir to avoid core file related races.
-TEST_WORKDIR=$OUTPUT_ROOT/build/test-work/$TEST_NAME
-mkdir -p $TEST_WORKDIR
-pushd $TEST_WORKDIR >/dev/null || exit 1
-rm -f *
-
-set -o pipefail
-
-LOGFILE=$TEST_LOGDIR/$TEST_NAME.txt
-XMLFILE=$TEST_LOGDIR/$TEST_NAME.xml
-
-TEST_EXECUTION_ATTEMPTS=1
-
-# Remove both the uncompressed output, so the developer doesn't accidentally get confused
-# and read output from a prior test run.
-rm -f $LOGFILE $LOGFILE.gz
-
-pipe_cmd=cat
-
-# Allow for collecting core dumps.
-PARQUET_TEST_ULIMIT_CORE=${PARQUET_TEST_ULIMIT_CORE:-0}
-ulimit -c $PARQUET_TEST_ULIMIT_CORE
-
-
-function setup_sanitizers() {
-  # Sets environment variables for different sanitizers (it configures how) the run_tests. Function works.
-
-  # Configure TSAN (ignored if this isn't a TSAN build).
-  #
-  # Deadlock detection (new in clang 3.5) is disabled because:
-  # 1. The clang 3.5 deadlock detector crashes in some unit tests. It
-  #    needs compiler-rt commits c4c3dfd, 9a8efe3, and possibly others.
-  # 2. Many unit tests report lock-order-inversion warnings; they should be
-  #    fixed before reenabling the detector.
-  TSAN_OPTIONS="$TSAN_OPTIONS detect_deadlocks=0"
-  TSAN_OPTIONS="$TSAN_OPTIONS suppressions=$ROOT/build-support/tsan-suppressions.txt"
-  TSAN_OPTIONS="$TSAN_OPTIONS history_size=7"
-  export TSAN_OPTIONS
-
-  # Enable leak detection even under LLVM 3.4, where it was disabled by default.
-  # This flag only takes effect when running an ASAN build.
-  ASAN_OPTIONS="$ASAN_OPTIONS detect_leaks=1"
-  export ASAN_OPTIONS
-
-  # Set up suppressions for LeakSanitizer
-  LSAN_OPTIONS="$LSAN_OPTIONS suppressions=$ROOT/build-support/lsan-suppressions.txt"
-  export LSAN_OPTIONS
-
-  # Suppressions require symbolization. We'll default to using the symbolizer in
-  # thirdparty.
-  if [ -z "$ASAN_SYMBOLIZER_PATH" ]; then
-    export ASAN_SYMBOLIZER_PATH=$(find $NATIVE_TOOLCHAIN/llvm-3.7.0/bin -name llvm-symbolizer)
-  fi
-}
-
-function run_test() {
-  # Run gtest style tests with sanitizers if they are setup appropriately.
-
-  # gtest won't overwrite old junit test files, resulting in a build failure
-  # even when retries are successful.
-  rm -f $XMLFILE
-
-  # This is needed for test execution on macOS with shared arrow linkage build
-  # via external project.
-  export LD_LIBRARY_PATH=${TEST_DIRNAME}:$LD_LIBRARY_PATH
-  $TEST_EXECUTABLE "$@" 2>&1 \
-    | c++filt \
-    | $ROOT/build-support/stacktrace_addr2line.pl $TEST_EXECUTABLE \
-    | $pipe_cmd 2>&1 | tee $LOGFILE
-  STATUS=$?
-
-  # TSAN doesn't always exit with a non-zero exit code due to a bug:
-  # mutex errors don't get reported through the normal error reporting infrastructure.
-  # So we make sure to detect this and exit 1.
-  #
-  # Additionally, certain types of failures won't show up in the standard JUnit
-  # XML output from gtest. We assume that gtest knows better than us and our
-  # regexes in most cases, but for certain errors we delete the resulting xml
-  # file and let our own post-processing step regenerate it.
-  export GREP=$(which egrep)
-  if zgrep --silent "ThreadSanitizer|Leak check.*detected leaks" $LOGFILE ; then
-    echo ThreadSanitizer or leak check failures in $LOGFILE
-    STATUS=1
-    rm -f $XMLFILE
-  fi
-}
-
-function post_process_tests() {
-  # If we have a LeakSanitizer report, and XML reporting is configured, add a new test
-  # case result to the XML file for the leak report. Otherwise Jenkins won't show
-  # us which tests had LSAN errors.
-  if zgrep --silent "ERROR: LeakSanitizer: detected memory leaks" $LOGFILE ; then
-      echo Test had memory leaks. Editing XML
-      perl -p -i -e '
-      if (m#</testsuite>#) {
-        print "<testcase name=\"LeakSanitizer\" status=\"run\" classname=\"LSAN\">\n";
-        print "  <failure message=\"LeakSanitizer failed\" type=\"\">\n";
-        print "    See txt log file for details\n";
-        print "  </failure>\n";
-        print "</testcase>\n";
-      }' $XMLFILE
-  fi
-}
-
-function run_other() {
-  # Generic run function for test like executables that aren't actually gtest
-  $TEST_EXECUTABLE "$@" 2>&1 | $pipe_cmd > $LOGFILE
-  STATUS=$?
-}
-
-if [ $RUN_TYPE = "test" ]; then
-    setup_sanitizers
-fi
-
-# Run the actual test.
-for ATTEMPT_NUMBER in $(seq 1 $TEST_EXECUTION_ATTEMPTS) ; do
-  if [ $ATTEMPT_NUMBER -lt $TEST_EXECUTION_ATTEMPTS ]; then
-    # If the test fails, the test output may or may not be left behind,
-    # depending on whether the test cleaned up or exited immediately. Either
-    # way we need to clean it up. We do this by comparing the data directory
-    # contents before and after the test runs, and deleting anything new.
-    #
-    # The comm program requires that its two inputs be sorted.
-    TEST_TMPDIR_BEFORE=$(find $TEST_TMPDIR -maxdepth 1 -type d | sort)
-  fi
-
-  if [ $ATTEMPT_NUMBER -lt $TEST_EXECUTION_ATTEMPTS ]; then
-    # Now delete any new test output.
-    TEST_TMPDIR_AFTER=$(find $TEST_TMPDIR -maxdepth 1 -type d | sort)
-    DIFF=$(comm -13 <(echo "$TEST_TMPDIR_BEFORE") \
-                    <(echo "$TEST_TMPDIR_AFTER"))
-    for DIR in $DIFF; do
-      # Multiple tests may be running concurrently. To avoid deleting the
-      # wrong directories, constrain to only directories beginning with the
-      # test name.
-      #
-      # This may delete old test directories belonging to this test, but
-      # that's not typically a concern when rerunning flaky tests.
-      if [[ $DIR =~ ^$TEST_TMPDIR/$TEST_NAME ]]; then
-        echo Deleting leftover flaky test directory "$DIR"
-        rm -Rf "$DIR"
-      fi
-    done
-  fi
-  echo "Running $TEST_NAME, redirecting output into $LOGFILE" \
-       "(attempt ${ATTEMPT_NUMBER}/$TEST_EXECUTION_ATTEMPTS)"
-  if [ $RUN_TYPE = "test" ]; then
-    run_test $*
-  else
-    run_other $*
-  fi
-  if [ "$STATUS" -eq "0" ]; then
-    break
-  elif [ "$ATTEMPT_NUMBER" -lt "$TEST_EXECUTION_ATTEMPTS" ]; then
-    echo Test failed attempt number $ATTEMPT_NUMBER
-    echo Will retry...
-  fi
-done
-
-if [ $RUN_TYPE = "test" ]; then
-  post_process_tests
-fi
-
-# Capture and compress core file and binary.
-COREFILES=$(ls | grep ^core)
-if [ -n "$COREFILES" ]; then
-  echo Found core dump. Saving executable and core files.
-  gzip < $TEST_EXECUTABLE > "$TEST_DEBUGDIR/$TEST_NAME.gz" || exit $?
-  for COREFILE in $COREFILES; do
-    gzip < $COREFILE > "$TEST_DEBUGDIR/$TEST_NAME.$COREFILE.gz" || exit $?
-  done
-  # Pull in any .so files as well.
-  for LIB in $(ldd $TEST_EXECUTABLE | grep $ROOT | awk '{print $3}'); do
-    LIB_NAME=$(basename $LIB)
-    gzip < $LIB > "$TEST_DEBUGDIR/$LIB_NAME.gz" || exit $?
-  done
-fi
-
-popd
-rm -Rf $TEST_WORKDIR
-
-exit $STATUS
diff --git a/build-support/run_clang_format.py b/build-support/run_clang_format.py
deleted file mode 100755
index 6dec34b..0000000
--- a/build-support/run_clang_format.py
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/usr/bin/env python
-# 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.
-
-import fnmatch
-import os
-import subprocess
-import sys
-
-if len(sys.argv) < 4:
-    sys.stderr.write("Usage: %s $CLANG_FORMAT_VERSION exclude_globs.txt "
-                     "$source_dir\n" %
-                     sys.argv[0])
-    sys.exit(1)
-
-CLANG_FORMAT = sys.argv[1]
-EXCLUDE_GLOBS_FILENAME = sys.argv[2]
-SOURCE_DIR = sys.argv[3]
-
-if len(sys.argv) > 4:
-    CHECK_FORMAT = int(sys.argv[4]) == 1
-else:
-    CHECK_FORMAT = False
-
-
-exclude_globs = [line.strip() for line in open(EXCLUDE_GLOBS_FILENAME, "r")]
-
-files_to_format = []
-matches = []
-for directory, subdirs, files in os.walk(SOURCE_DIR):
-    for name in files:
-        name = os.path.join(directory, name)
-        if not (name.endswith('.h') or name.endswith('.cc')):
-            continue
-
-        excluded = False
-        for g in exclude_globs:
-            if fnmatch.fnmatch(name, g):
-                excluded = True
-                break
-        if not excluded:
-            files_to_format.append(name)
-
-if CHECK_FORMAT:
-    output = subprocess.check_output([CLANG_FORMAT, '-output-replacements-xml']
-                                     + files_to_format,
-                                     stderr=subprocess.STDOUT).decode('utf8')
-
-    to_fix = []
-    for line in output.split('\n'):
-        if 'offset' in line:
-            to_fix.append(line)
-
-    if len(to_fix) > 0:
-        print("clang-format checks failed, run 'make format' to fix")
-        sys.exit(-1)
-else:
-    try:
-        cmd = [CLANG_FORMAT, '-i'] + files_to_format
-        subprocess.check_output(cmd, stderr=subprocess.STDOUT)
-    except Exception as e:
-        print(e)
-        print(' '.join(cmd))
-        raise
diff --git a/build-support/stacktrace_addr2line.pl b/build-support/stacktrace_addr2line.pl
deleted file mode 100755
index f407247..0000000
--- a/build-support/stacktrace_addr2line.pl
+++ /dev/null
@@ -1,95 +0,0 @@
-#!/usr/bin/env perl
-# 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.
-#######################################################################
-# This script will convert a stack trace with addresses:
-#     @           0x5fb015 kudu::master::Master::Init()
-#     @           0x5c2d38 kudu::master::MiniMaster::StartOnPorts()
-#     @           0x5c31fa kudu::master::MiniMaster::Start()
-#     @           0x58270a kudu::MiniCluster::Start()
-#     @           0x57dc71 kudu::CreateTableStressTest::SetUp()
-# To one with line numbers:
-#     @           0x5fb015 kudu::master::Master::Init() at /home/mpercy/src/kudu/src/master/master.cc:54
-#     @           0x5c2d38 kudu::master::MiniMaster::StartOnPorts() at /home/mpercy/src/kudu/src/master/mini_master.cc:52
-#     @           0x5c31fa kudu::master::MiniMaster::Start() at /home/mpercy/src/kudu/src/master/mini_master.cc:33
-#     @           0x58270a kudu::MiniCluster::Start() at /home/mpercy/src/kudu/src/integration-tests/mini_cluster.cc:48
-#     @           0x57dc71 kudu::CreateTableStressTest::SetUp() at /home/mpercy/src/kudu/src/integration-tests/create-table-stress-test.cc:61
-#
-# If the script detects that the output is not symbolized, it will also attempt
-# to determine the function names, i.e. it will convert:
-#     @           0x5fb015
-#     @           0x5c2d38
-#     @           0x5c31fa
-# To:
-#     @           0x5fb015 kudu::master::Master::Init() at /home/mpercy/src/kudu/src/master/master.cc:54
-#     @           0x5c2d38 kudu::master::MiniMaster::StartOnPorts() at /home/mpercy/src/kudu/src/master/mini_master.cc:52
-#     @           0x5c31fa kudu::master::MiniMaster::Start() at /home/mpercy/src/kudu/src/master/mini_master.cc:33
-#######################################################################
-use strict;
-use warnings;
-
-if (!@ARGV) {
-  die <<EOF
-Usage: $0 executable [stack-trace-file]
-
-This script will read addresses from a file containing stack traces and
-will convert the addresses that conform to the pattern " @ 0x123456" to line
-numbers by calling addr2line on the provided executable.
-If no stack-trace-file is specified, it will take input from stdin.
-EOF
-}
-
-# el6 and other older systems don't support the -p flag,
-# so we do our own "pretty" parsing.
-sub parse_addr2line_output($$) {
-  defined(my $output = shift) or die;
-  defined(my $lookup_func_name = shift) or die;
-  my @lines = grep { $_ ne '' } split("\n", $output);
-  my $pretty_str = '';
-  if ($lookup_func_name) {
-    $pretty_str .= ' ' . $lines[0];
-  }
-  $pretty_str .= ' at ' . $lines[1];
-  return $pretty_str;
-}
-
-my $binary = shift @ARGV;
-if (! -x $binary || ! -r $binary) {
-  die "Error: Cannot access executable ($binary)";
-}
-
-# Cache lookups to speed processing of files with repeated trace addresses.
-my %addr2line_map = ();
-
-# Disable stdout buffering
-$| = 1;
-
-# Reading from <ARGV> is magical in Perl.
-while (defined(my $input = <ARGV>)) {
-  if ($input =~ /^\s+\@\s+(0x[[:xdigit:]]{6,})(?:\s+(\S+))?/) {
-    my $addr = $1;
-    my $lookup_func_name = (!defined $2);
-    if (!exists($addr2line_map{$addr})) {
-      $addr2line_map{$addr} = `addr2line -ifC -e $binary $addr`;
-    }
-    chomp $input;
-    $input .= parse_addr2line_output($addr2line_map{$addr}, $lookup_func_name) . "\n";
-  }
-  print $input;
-}
-
-exit 0;
diff --git a/ci/before_script_travis.sh b/ci/before_script_travis.sh
deleted file mode 100755
index ce0234c..0000000
--- a/ci/before_script_travis.sh
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/env bash
-
-#  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. See accompanying LICENSE file.
-
-if [ $TRAVIS_OS_NAME == "osx" ]; then
-  brew update > /dev/null
-  brew install boost
-  brew install openssl
-  brew install bison
-  export OPENSSL_ROOT_DIR=/usr/local/opt/openssl
-  export LD_LIBRARY_PATH=/usr/local/opt/openssl/lib:$LD_LIBRARY_PATH
-  export PATH="/usr/local/opt/bison/bin:$PATH"
-else
-  # Use a C++11 compiler on Linux
-  export CC="gcc-4.9"
-  export CXX="g++-4.9"
-fi
-
-export PARQUET_TEST_DATA=$TRAVIS_BUILD_DIR/data
-
-CMAKE_COMMON_FLAGS="-DPARQUET_BUILD_WARNING_LEVEL=CHECKIN"
-
-if [ $PARQUET_TRAVIS_VALGRIND == "1" ]; then
-  CMAKE_COMMON_FLAGS="$CMAKE_COMMON_FLAGS -DPARQUET_TEST_MEMCHECK=ON"
-fi
-
-if [ $TRAVIS_OS_NAME == "linux" ]; then
-    cmake $CMAKE_COMMON_FLAGS \
-          -DPARQUET_CXXFLAGS="$PARQUET_CXXFLAGS" \
-          -DPARQUET_BUILD_BENCHMARKS=ON \
-          -DPARQUET_GENERATE_COVERAGE=1 \
-          $TRAVIS_BUILD_DIR
-else
-    cmake $CMAKE_COMMON_FLAGS \
-          -DPARQUET_CXXFLAGS="$PARQUET_CXXFLAGS" \
-          $TRAVIS_BUILD_DIR
-fi
diff --git a/ci/msvc-build.bat b/ci/msvc-build.bat
deleted file mode 100644
index 7a50c85..0000000
--- a/ci/msvc-build.bat
+++ /dev/null
@@ -1,77 +0,0 @@
-@rem Licensed to the Apache Software Foundation (ASF) under one
-@rem or more contributor license agreements.  See the NOTICE file
-@rem distributed with this work for additional information
-@rem regarding copyright ownership.  The ASF licenses this file
-@rem to you under the Apache License, Version 2.0 (the
-@rem "License"); you may not use this file except in compliance
-@rem with the License.  You may obtain a copy of the License at
-@rem
-@rem   http://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing,
-@rem software distributed under the License is distributed on an
-@rem "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-@rem KIND, either express or implied.  See the License for the
-@rem specific language governing permissions and limitations
-@rem under the License.
-
-@echo on
-
-mkdir build
-cd build
-
-SET PARQUET_TEST_DATA=%APPVEYOR_BUILD_FOLDER%\data
-set PARQUET_CXXFLAGS=/MP
-
-set PARQUET_USE_STATIC_CRT_OPTION=OFF
-if "%USE_STATIC_CRT%" == "ON" (
-      set PARQUET_USE_STATIC_CRT_OPTION=ON
-)
-
-if NOT "%CONFIGURATION%" == "Debug" (
-  set PARQUET_CXXFLAGS="%PARQUET_CXXFLAGS% /WX"
-)
-
-if "%GENERATOR%"=="NMake Makefiles" set need_vcvarsall=1
-
-if defined need_vcvarsall (
-    @rem Select desired compiler version
-    if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2017" (
-        call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64
-    ) else (
-        call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
-    )
-)
-
-if "%CONFIGURATION%" == "Toolchain" (
-  conda install -y boost-cpp=1.63 thrift-cpp=0.11.0 ^
-      brotli=1.0.2 zlib=1.2.11 snappy=1.1.7 lz4-c=1.8.0 zstd=1.3.3 ^
-      -c conda-forge || exit /B
-
-  set ARROW_BUILD_TOOLCHAIN=%MINICONDA%/Library
-  set PARQUET_BUILD_TOOLCHAIN=%MINICONDA%/Library
-
-  cmake -G "%GENERATOR%" ^
-      -DCMAKE_BUILD_TYPE=Release ^
-      -DPARQUET_BOOST_USE_SHARED=OFF ^
-      -DPARQUET_CXXFLAGS=%PARQUET_CXXFLAGS% ^
-      .. || exit /B
-
-  cmake --build . --config Release || exit /B
-)
-
-if NOT "%CONFIGURATION%" == "Toolchain" (
-  cmake -G "%GENERATOR%" ^
-        -DCMAKE_BUILD_TYPE=%CONFIGURATION% ^
-        -DPARQUET_BOOST_USE_SHARED=OFF ^
-        -DPARQUET_CXXFLAGS=%PARQUET_CXXFLAGS% ^
-        -DPARQUET_USE_STATIC_CRT=%PARQUET_USE_STATIC_CRT_OPTION% ^
-        .. || exit /B
-
-  cmake --build . --config %CONFIGURATION% || exit /B
-)
-
-if NOT "%CONFIGURATION%" == "Debug" (
-    @rem Tests are too slow and/or hang in debug mode
-    ctest -VV || exit /B
-)
diff --git a/ci/travis_script_cpp.sh b/ci/travis_script_cpp.sh
deleted file mode 100755
index 3031363..0000000
--- a/ci/travis_script_cpp.sh
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/env bash
-
-#  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. See accompanying LICENSE file.
-
-set -xe
-
-: ${CPP_BUILD_DIR=$TRAVIS_BUILD_DIR/parquet-build}
-
-# Check licenses according to Apache policy
-pushd $TRAVIS_BUILD_DIR
-git archive HEAD -o parquet-cpp-src.tar.gz
-$TRAVIS_BUILD_DIR/dev/release/run-rat.sh parquet-cpp-src.tar.gz
-popd
-
-pushd $CPP_BUILD_DIR
-
-make lint
-
-# PARQUET-626: disabled check for now
-# if [ $TRAVIS_OS_NAME == "linux" ]; then
-#   make check-format
-#   make check-clang-tidy
-# fi
-
-if [ $TRAVIS_OS_NAME == "linux" ]; then
-  make -j4
-  ctest -j2 -VV -L unittest
-# Current cpp-coveralls version 0.4 throws an error (PARQUET-1075) on Travis CI. Pin to last working version
-  sudo pip install cpp_coveralls==0.3.12
-  export PARQUET_ROOT=$TRAVIS_BUILD_DIR
-  $TRAVIS_BUILD_DIR/ci/upload_coverage.sh
-else
-  make -j4
-  BUILD_TYPE=debug
-  EXECUTABLE_DIR=$CPP_BUILD_DIR/$BUILD_TYPE
-  export LD_LIBRARY_PATH=$EXECUTABLE_DIR:$LD_LIBRARY_PATH
-  ctest -j2 -VV -L unittest
-fi
-
-popd
diff --git a/ci/travis_script_static.sh b/ci/travis_script_static.sh
deleted file mode 100755
index 8af574e..0000000
--- a/ci/travis_script_static.sh
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/usr/bin/env bash
-
-#  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. See accompanying LICENSE file.
-
-set -xe
-
-# Use a C++11 compiler on Linux
-export CC="gcc-4.9"
-export CXX="g++-4.9"
-
-# ----------------------------------------------------------------------
-# Set up external toolchain
-
-MINICONDA_URL="https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh"
-export MINICONDA=$HOME/miniconda
-wget -O miniconda.sh $MINICONDA_URL
-bash miniconda.sh -b -p $MINICONDA
-export PATH="$MINICONDA/bin:$PATH"
-export CPP_TOOLCHAIN=$TRAVIS_BUILD_DIR/cpp-toolchain
-
-conda update -y -q conda
-conda config --set auto_update_conda false
-conda info -a
-
-conda config --set show_channel_urls True
-
-# Help with SSL timeouts to S3
-conda config --set remote_connect_timeout_secs 12
-
-conda info -a
-
-conda create -y -q -p $CPP_TOOLCHAIN \
-      boost-cpp thrift-cpp=0.10.0 cmake git \
-      -c conda-forge
-
-source activate $CPP_TOOLCHAIN
-
-# ----------------------------------------------------------------------
-
-: ${CPP_BUILD_DIR=$TRAVIS_BUILD_DIR/parquet-build}
-export PARQUET_TEST_DATA=$TRAVIS_BUILD_DIR/data
-export PARQUET_BUILD_TOOLCHAIN=$CPP_TOOLCHAIN
-export LD_LIBRARY_PATH=$CPP_TOOLCHAIN/lib:$LD_LIBRARY_PATH
-export BOOST_ROOT=$CPP_TOOLCHAIN
-export PARQUET_TEST_DATA=$TRAVIS_BUILD_DIR/data
-
-ARROW_EP=$TRAVIS_BUILD_DIR/parquet-build/arrow_ep-prefix/src/arrow_ep-build
-BROTLI_EP=$ARROW_EP/brotli_ep/src/brotli_ep-install/lib/x86_64-linux-gnu
-
-export SNAPPY_STATIC_LIB=$ARROW_EP/snappy_ep/src/snappy_ep-install/lib/libsnappy.a
-export BROTLI_STATIC_LIB_ENC=$BROTLI_EP/libbrotlienc.a
-export BROTLI_STATIC_LIB_DEC=$BROTLI_EP/libbrotlidec.a
-export BROTLI_STATIC_LIB_COMMON=$BROTLI_EP/libbrotlicommon.a
-export ZLIB_STATIC_LIB=$ARROW_EP/zlib_ep/src/zlib_ep-install/lib/libz.a
-export LZ4_STATIC_LIB=$ARROW_EP/lz4_ep-prefix/src/lz4_ep/lib/liblz4.a
-export ZSTD_STATIC_LIB=$ARROW_EP/zstd_ep-prefix/src/zstd_ep/lib/libzstd.a
-
-CMAKE_COMMON_FLAGS="-DPARQUET_BUILD_WARNING_LEVEL=CHECKIN"
-
-if [ $PARQUET_TRAVIS_VALGRIND == "1" ]; then
-  CMAKE_COMMON_FLAGS="$CMAKE_COMMON_FLAGS -DPARQUET_TEST_MEMCHECK=ON"
-fi
-
-cmake $CMAKE_COMMON_FLAGS \
-      -DPARQUET_CXXFLAGS="$PARQUET_CXXFLAGS" \
-      -DPARQUET_ARROW_LINKAGE="static" \
-      -DPARQUET_BUILD_SHARED=OFF \
-      -DPARQUET_BOOST_USE_SHARED=OFF \
-      -DPARQUET_THRIFT_USE_BOOST=ON \
-      -DPARQUET_BUILD_BENCHMARKS=ON \
-      -DPARQUET_BUILD_EXAMPLES=ON \
-      -DPARQUET_GENERATE_COVERAGE=1 \
-      $TRAVIS_BUILD_DIR
-
-pushd $CPP_BUILD_DIR
-
-make -j4 VERBOSE=1
-ctest -j2 -VV -L unittest
-
-popd
diff --git a/ci/travis_script_toolchain.sh b/ci/travis_script_toolchain.sh
deleted file mode 100755
index e94552c..0000000
--- a/ci/travis_script_toolchain.sh
+++ /dev/null
@@ -1,88 +0,0 @@
-#!/usr/bin/env bash
-
-#  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. See accompanying LICENSE file.
-
-set -xe
-
-# Use a C++11 compiler on Linux
-export CC="gcc-4.9"
-export CXX="g++-4.9"
-
-# ----------------------------------------------------------------------
-# Set up external toolchain
-
-MINICONDA_URL="https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh"
-export MINICONDA=$HOME/miniconda
-wget -O miniconda.sh $MINICONDA_URL
-bash miniconda.sh -b -p $MINICONDA
-export PATH="$MINICONDA/bin:$PATH"
-export CPP_TOOLCHAIN=$TRAVIS_BUILD_DIR/cpp-toolchain
-
-conda update -y -q conda
-conda config --set auto_update_conda false
-conda info -a
-
-conda config --set show_channel_urls True
-
-# Help with SSL timeouts to S3
-conda config --set remote_connect_timeout_secs 12
-
-conda info -a
-
-conda create -y -q -p $CPP_TOOLCHAIN \
-      boost-cpp thrift-cpp=0.11.0 cmake git \
-      -c conda-forge
-
-# ----------------------------------------------------------------------
-
-: ${CPP_BUILD_DIR=$TRAVIS_BUILD_DIR/parquet-build}
-export PARQUET_TEST_DATA=$TRAVIS_BUILD_DIR/data
-export PARQUET_BUILD_TOOLCHAIN=$CPP_TOOLCHAIN
-export LD_LIBRARY_PATH=$CPP_TOOLCHAIN/lib:$LD_LIBRARY_PATH
-export BOOST_ROOT=$CPP_TOOLCHAIN
-
-CMAKE_COMMON_FLAGS="-DPARQUET_BUILD_WARNING_LEVEL=CHECKIN"
-
-if [ $PARQUET_TRAVIS_VALGRIND == "1" ]; then
-  CMAKE_COMMON_FLAGS="$CMAKE_COMMON_FLAGS -DPARQUET_TEST_MEMCHECK=ON"
-fi
-
-cmake $CMAKE_COMMON_FLAGS \
-      -DPARQUET_CXXFLAGS=-Werror \
-      -DPARQUET_GENERATE_COVERAGE=1 \
-      -DCMAKE_INSTALL_PREFIX=$CPP_TOOLCHAIN \
-      $TRAVIS_BUILD_DIR
-
-pushd $CPP_BUILD_DIR
-
-make -j4
-make install
-ctest -j2 -VV -L unittest
-
-popd
-
-# Build and run the parquet::arrow example. This also tests the usage of parquet-cpp as a library.
-
-pushd $TRAVIS_BUILD_DIR/examples/parquet-arrow
-mkdir build
-pushd build
-
-export ARROW_HOME=$CPP_TOOLCHAIN
-export PARQUET_HOME=$CPP_TOOLCHAIN
-
-cmake ..
-make VERBOSE=1
-./parquet-arrow-reader-writer
-
-popd
-popd
diff --git a/ci/upload_coverage.sh b/ci/upload_coverage.sh
deleted file mode 100755
index 73b37c2..0000000
--- a/ci/upload_coverage.sh
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/env bash
-
-#  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. See accompanying LICENSE file.
-
-set -e
-set -x
-
-ROOT_DIR=$(cd "$(dirname "$BASH_SOURCE")"; pwd)
-
-mkdir coverage_artifacts
-python $ROOT_DIR/../build-support/collect_coverage.py CMakeFiles/parquet.dir/src/ coverage_artifacts
-
-cd coverage_artifacts
-
-ls -l
-
-echo $PARQUET_ROOT
-
-coveralls --gcov $(which gcov-4.9) \
-    --gcov-options '\-l' --root '' \
-    --include $PARQUET_ROOT \
-    --exclude $PARQUET_ROOT/parquet-build/thirdparty \
-    --exclude $PARQUET_ROOT/parquet-build/arrow_ep \
-    --exclude $PARQUET_ROOT/parquet-build/brotli_ep \
-    --exclude $PARQUET_ROOT/parquet-build/brotli_ep-prefix \
-    --exclude $PARQUET_ROOT/parquet-build/gbenchmark_ep \
-    --exclude $PARQUET_ROOT/parquet-build/googletest_ep-prefix \
-    --exclude $PARQUET_ROOT/parquet-build/snappy_ep \
-    --exclude $PARQUET_ROOT/parquet-build/snappy_ep-prefix \
-    --exclude $PARQUET_ROOT/parquet-build/zlib_ep \
-    --exclude $PARQUET_ROOT/parquet-build/zlib_ep-prefix \
-    --exclude $PARQUET_ROOT/build \
-    --exclude $PARQUET_ROOT/src/parquet/thrift \
-    --exclude /usr
diff --git a/cmake_modules/ArrowExternalProject.cmake b/cmake_modules/ArrowExternalProject.cmake
deleted file mode 100644
index 51eeca5..0000000
--- a/cmake_modules/ArrowExternalProject.cmake
+++ /dev/null
@@ -1,75 +0,0 @@
-# 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.
-
-set(ARROW_PREFIX "${BUILD_OUTPUT_ROOT_DIRECTORY}")
-set(ARROW_INCLUDE_DIR "${ARROW_PREFIX}/include")
-set(ARROW_LIB_DIR "${ARROW_PREFIX}")
-if (MSVC)
-  set(ARROW_SHARED_LIB "${ARROW_PREFIX}/bin/arrow.dll")
-  set(ARROW_SHARED_IMPLIB "${ARROW_LIB_DIR}/arrow.lib")
-  set(ARROW_STATIC_LIB "${ARROW_LIB_DIR}/arrow_static.lib")
-else()
-  set(ARROW_SHARED_LIB "${ARROW_LIB_DIR}/libarrow${CMAKE_SHARED_LIBRARY_SUFFIX}")
-  set(ARROW_STATIC_LIB "${ARROW_LIB_DIR}/libarrow.a")
-endif()
-
-set(ARROW_CMAKE_ARGS
-  -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-  -DCMAKE_CXX_FLAGS=${EP_CXX_FLAGS}
-  -DCMAKE_C_FLAGS=${EP_C_FLAGS}
-  -DCMAKE_INSTALL_PREFIX=${ARROW_PREFIX}
-  -DCMAKE_INSTALL_LIBDIR=${ARROW_LIB_DIR}
-  -DARROW_JEMALLOC=OFF
-  -DARROW_IPC=OFF
-  -DARROW_WITH_LZ4=ON
-  -DARROW_WITH_ZSTD=ON
-  -DARROW_BUILD_SHARED=${PARQUET_BUILD_SHARED}
-  -DARROW_BOOST_USE_SHARED=${PARQUET_BOOST_USE_SHARED}
-  -DARROW_BUILD_TESTS=OFF)
-
-if (MSVC AND PARQUET_USE_STATIC_CRT)
-  set(ARROW_CMAKE_ARGS ${ARROW_CMAKE_ARGS} -DARROW_USE_STATIC_CRT=ON)
-endif()
-
-if ("$ENV{PARQUET_ARROW_VERSION}" STREQUAL "")
-  # This can be a tag or changeset
-  set(ARROW_VERSION "170dc75468efbad2286c630b9103d1aacdb6bada")
-else()
-  set(ARROW_VERSION "$ENV{PARQUET_ARROW_VERSION}")
-endif()
-message(STATUS "Building Apache Arrow from commit: ${ARROW_VERSION}")
-
-set(ARROW_URL "https://github.com/apache/arrow/archive/${ARROW_VERSION}.tar.gz")
-
-if (CMAKE_VERSION VERSION_GREATER "3.7")
-  set(ARROW_CONFIGURE SOURCE_SUBDIR "cpp" CMAKE_ARGS ${ARROW_CMAKE_ARGS})
-else()
-  set(ARROW_CONFIGURE CONFIGURE_COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}"
-    ${ARROW_CMAKE_ARGS} "${CMAKE_CURRENT_BINARY_DIR}/arrow_ep-prefix/src/arrow_ep/cpp")
-endif()
-
-ExternalProject_Add(arrow_ep
-  URL ${ARROW_URL}
-  ${ARROW_CONFIGURE}
-  BUILD_BYPRODUCTS "${ARROW_SHARED_LIB}" "${ARROW_STATIC_LIB}")
-
-if (MSVC)
-  ExternalProject_Add_Step(arrow_ep copy_dll_step
-    DEPENDEES install
-    COMMAND ${CMAKE_COMMAND} -E make_directory ${BUILD_OUTPUT_ROOT_DIRECTORY}
-    COMMAND ${CMAKE_COMMAND} -E copy ${ARROW_SHARED_LIB} ${BUILD_OUTPUT_ROOT_DIRECTORY})
-endif()
diff --git a/cmake_modules/BuildUtils.cmake b/cmake_modules/BuildUtils.cmake
deleted file mode 100644
index 1ce891c..0000000
--- a/cmake_modules/BuildUtils.cmake
+++ /dev/null
@@ -1,112 +0,0 @@
-# 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.
-
-function(ADD_LIB LIB_NAME)
-  set(options)
-  set(one_value_args SHARED_LINK_FLAGS ABI_VERSION SO_VERSION LIB_BUILD_SHARED LIB_BUILD_STATIC)
-  set(multi_value_args SOURCES STATIC_LINK_LIBS STATIC_PRIVATE_LINK_LIBS SHARED_LINK_LIBS SHARED_PRIVATE_LINK_LIBS DEPENDENCIES)
-  cmake_parse_arguments(ARG "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN})
-  if(ARG_UNPARSED_ARGUMENTS)
-    message(SEND_ERROR "Error: unrecognized arguments: ${ARG_UNPARSED_ARGUMENTS}")
-  endif()
-
-  add_library(${LIB_NAME}_objlib OBJECT
-    ${ARG_SOURCES})
-
-  if (ARG_DEPENDENCIES)
-    add_dependencies(${LIB_NAME}_objlib ${ARG_DEPENDENCIES})
-  endif()
-
-  # Necessary to make static linking into other shared libraries work properly
-  set_property(TARGET ${LIB_NAME}_objlib PROPERTY POSITION_INDEPENDENT_CODE 1)
-
-  set(RUNTIME_INSTALL_DIR bin)
-
-  if (ARG_LIB_BUILD_SHARED)
-    add_library(${LIB_NAME}_shared SHARED $<TARGET_OBJECTS:${LIB_NAME}_objlib>)
-
-    if(APPLE)
-      # On OS X, you can avoid linking at library load time and instead
-      # expecting that the symbols have been loaded separately. This happens
-      # with libpython* where there can be conflicts between system Python and
-      # the Python from a thirdparty distribution
-      set(ARG_SHARED_LINK_FLAGS
-        "-undefined dynamic_lookup ${ARG_SHARED_LINK_FLAGS}")
-    endif()
-
-    set_target_properties(${LIB_NAME}_shared
-      PROPERTIES
-      LIBRARY_OUTPUT_DIRECTORY "${BUILD_OUTPUT_ROOT_DIRECTORY}"
-      RUNTIME_OUTPUT_DIRECTORY "${BUILD_OUTPUT_ROOT_DIRECTORY}"
-      PDB_OUTPUT_DIRECTORY "${BUILD_OUTPUT_ROOT_DIRECTORY}"
-      LINK_FLAGS "${ARG_SHARED_LINK_FLAGS}"
-      OUTPUT_NAME ${LIB_NAME}
-      VERSION "${ARG_ABI_VERSION}"
-      SOVERSION "${ARG_SO_VERSION}")
-
-    if (ARG_SHARED_LINK_LIBS OR ARG_SHARED_PRIVATE_LINK_LIBS)
-      target_link_libraries(${LIB_NAME}_shared
-        LINK_PUBLIC ${ARG_SHARED_LINK_LIBS}
-        LINK_PRIVATE ${ARG_SHARED_PRIVATE_LINK_LIBS})
-    endif()
-
-    if (PARQUET_RPATH_ORIGIN)
-        if (APPLE)
-            set(_lib_install_rpath "@loader_path")
-        else()
-            set(_lib_install_rpath "\$ORIGIN")
-        endif()
-        set_target_properties(${LIB_NAME}_shared PROPERTIES
-            INSTALL_RPATH ${_lib_install_rpath})
-    elseif (APPLE)
-      set_target_properties(${LIB_NAME}_shared
-        PROPERTIES
-        BUILD_WITH_INSTALL_RPATH ON
-        INSTALL_NAME_DIR "@rpath")
-    endif()
-
-    install(TARGETS ${LIB_NAME}_shared
-      RUNTIME DESTINATION ${RUNTIME_INSTALL_DIR}
-      LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
-      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
-  endif()
-
-  if (ARG_LIB_BUILD_STATIC)
-    if (MSVC)
-      set(LIB_NAME_STATIC ${LIB_NAME}_static)
-    else()
-      set(LIB_NAME_STATIC ${LIB_NAME})
-    endif()
-    add_library(${LIB_NAME}_static STATIC $<TARGET_OBJECTS:${LIB_NAME}_objlib>)
-    set_target_properties(${LIB_NAME}_static
-      PROPERTIES
-      LIBRARY_OUTPUT_DIRECTORY "${BUILD_OUTPUT_ROOT_DIRECTORY}"
-      OUTPUT_NAME ${LIB_NAME_STATIC})
-
-    if (ARG_STATIC_LINK_LIBS OR ARG_STATIC_PRIVATE_LINK_LIBS)
-      target_link_libraries(${LIB_NAME}_static
-        LINK_PUBLIC ${ARG_STATIC_LINK_LIBS}
-        LINK_PRIVATE ${ARG_STATIC_PRIVATE_LINK_LIBS})
-    endif()
-
-    install(TARGETS ${LIB_NAME}_static
-      RUNTIME DESTINATION ${RUNTIME_INSTALL_DIR}
-      LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
-      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
-  endif()
-
-endfunction()
diff --git a/cmake_modules/CompilerInfo.cmake b/cmake_modules/CompilerInfo.cmake
deleted file mode 100644
index 654a0d8..0000000
--- a/cmake_modules/CompilerInfo.cmake
+++ /dev/null
@@ -1,63 +0,0 @@
-# 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.
-#
-# Sets COMPILER_FAMILY to 'clang' or 'gcc' or 'msvc'
-# Sets COMPILER_VERSION to the version
-if(NOT MSVC)
-  set(COMPILER_GET_VERSION_SWITCH "-v")
-endif()
-
-execute_process(COMMAND "${CMAKE_CXX_COMPILER}" ${COMPILER_GET_VERSION_SWITCH}
-                OUTPUT_VARIABLE COMPILER_VERSION_FULL
-                ERROR_VARIABLE COMPILER_VERSION_FULL)
-message(STATUS "Compiler id: ${CMAKE_CXX_COMPILER_ID}")
-string(TOLOWER "${COMPILER_VERSION_FULL}" COMPILER_VERSION_FULL_LOWER)
-
-if(MSVC)
-  set(COMPILER_FAMILY "msvc")
-  if ("${COMPILER_VERSION_FULL}" MATCHES ".*Microsoft \\(R\\) C/C\\+\\+ Optimizing Compiler Version 19.*x64")
-    string(REGEX REPLACE ".*Optimizing Compiler Version ([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+).*" "\\1"
-      COMPILER_VERSION "${COMPILER_VERSION_FULL}")
-  elseif(NOT "${COMPILER_VERSION_FULL}" STREQUAL "")
-    message(FATAL_ERROR "Not supported MSVC compiler:\n${COMPILER_VERSION_FULL}\n"
-      "Supported MSVC versions: Visual Studio 2015 2017 x64")
-  endif()
-
-# clang on Linux and Mac OS X before 10.9
-elseif("${COMPILER_VERSION_FULL}" MATCHES ".*clang version.*")
-  set(COMPILER_FAMILY "clang")
-  string(REGEX REPLACE ".*clang version ([0-9]+\\.[0-9]+).*" "\\1"
-    COMPILER_VERSION "${COMPILER_VERSION_FULL}")
-# clang on Mac OS X 10.9 and later
-elseif("${COMPILER_VERSION_FULL}" MATCHES ".*based on LLVM.*")
-  set(COMPILER_FAMILY "clang")
-  string(REGEX REPLACE ".*based on LLVM ([0-9]+\\.[0.9]+).*" "\\1"
-    COMPILER_VERSION "${COMPILER_VERSION_FULL}")
-
-# clang on Mac OS X, XCode 7+.
-elseif("${COMPILER_VERSION_FULL}" MATCHES ".*clang-.*")
-  set(COMPILER_FAMILY "clang")
-  set(COMPILER_VERSION "4.0")
-# gcc
-elseif("${COMPILER_VERSION_FULL_LOWER}" MATCHES ".*gcc[ -]version.*")
-  set(COMPILER_FAMILY "gcc")
-  string(REGEX REPLACE ".*gcc[ -]version ([0-9\\.]+).*" "\\1"
-      COMPILER_VERSION "${COMPILER_VERSION_FULL_LOWER}")
-else()
-  message(FATAL_ERROR "Unknown compiler. Version info:\n${COMPILER_VERSION_FULL}")
-endif()
-message("Selected compiler ${COMPILER_FAMILY} ${COMPILER_VERSION}")
diff --git a/cmake_modules/FindArrow.cmake b/cmake_modules/FindArrow.cmake
deleted file mode 100644
index b63b1af..0000000
--- a/cmake_modules/FindArrow.cmake
+++ /dev/null
@@ -1,123 +0,0 @@
-# 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.
-
-# - Find ARROW (arrow/api.h, libarrow.a, libarrow.so)
-# This module defines
-#  ARROW_INCLUDE_DIR, directory containing headers
-#  ARROW_STATIC_LIB, path to libarrow.a
-#  ARROW_SHARED_LIB, path to libarrow's shared library
-#  ARROW_FOUND, whether arrow has been found
-
-if (DEFINED ENV{ARROW_HOME})
-  set(ARROW_HOME "$ENV{ARROW_HOME}")
-endif()
-
-if ("${ARROW_HOME}" STREQUAL "")
-  # PARQUET-955. If the user has set $ARROW_HOME in the environment, we respect
-  # this, otherwise try to locate the pkgconfig in the system environment
-  pkg_check_modules(ARROW arrow)
-  if (ARROW_FOUND)
-    # We found the pkgconfig
-    set(ARROW_INCLUDE_DIR ${ARROW_INCLUDE_DIRS})
-
-    if (COMMAND pkg_get_variable)
-      pkg_get_variable(ARROW_ABI_VERSION arrow abi_version)
-    else()
-      set(ARROW_ABI_VERSION "")
-    endif()
-    if (ARROW_ABI_VERSION STREQUAL "")
-      set(ARROW_SHARED_LIB_SUFFIX "")
-    else()
-      set(ARROW_SHARED_LIB_SUFFIX ".${ARROW_ABI_VERSION}")
-    endif()
-
-    set(ARROW_LIB_NAME ${CMAKE_SHARED_LIBRARY_PREFIX}arrow)
-
-    if (APPLE)
-      set(ARROW_SHARED_LIB ${ARROW_LIBDIR}/${ARROW_LIB_NAME}${ARROW_SHARED_LIB_SUFFIX}${CMAKE_SHARED_LIBRARY_SUFFIX})
-    else()
-      set(ARROW_SHARED_LIB ${ARROW_LIBDIR}/${ARROW_LIB_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX}${ARROW_SHARED_LIB_SUFFIX})
-    endif()
-    set(ARROW_STATIC_LIB ${ARROW_LIBDIR}/${ARROW_LIB_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX})
-  endif()
-else()
-  set(ARROW_HOME "${ARROW_HOME}")
-
-  if (MSVC AND NOT ARROW_MSVC_STATIC_LIB_SUFFIX)
-    set(ARROW_MSVC_STATIC_LIB_SUFFIX _static)
-  endif()
-
-  set(ARROW_SEARCH_HEADER_PATHS
-    ${ARROW_HOME}/include
-    )
-
-  set(ARROW_SEARCH_LIB_PATH
-    ${ARROW_HOME}/lib
-    )
-
-  find_path(ARROW_INCLUDE_DIR arrow/array.h PATHS
-    ${ARROW_SEARCH_HEADER_PATHS}
-    # make sure we don't accidentally pick up a different version
-    NO_DEFAULT_PATH
-    )
-
-  find_library(ARROW_LIB_PATH NAMES arrow arrow${ARROW_MSVC_STATIC_LIB_SUFFIX}
-    PATHS
-    ${ARROW_SEARCH_LIB_PATH}
-    NO_DEFAULT_PATH)
-
-  if (ARROW_INCLUDE_DIR AND (PARQUET_MINIMAL_DEPENDENCY OR ARROW_LIB_PATH))
-    set(ARROW_FOUND TRUE)
-    set(ARROW_HEADER_NAME arrow/api.h)
-    set(ARROW_HEADER ${ARROW_INCLUDE_DIR}/${ARROW_HEADER_NAME})
-    set(ARROW_LIB_NAME arrow)
-
-    get_filename_component(ARROW_LIBS ${ARROW_LIB_PATH} DIRECTORY)
-    set(ARROW_STATIC_LIB ${ARROW_LIBS}/${CMAKE_STATIC_LIBRARY_PREFIX}${ARROW_LIB_NAME}${ARROW_MSVC_STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX})
-    set(ARROW_SHARED_LIB ${ARROW_LIBS}/${CMAKE_SHARED_LIBRARY_PREFIX}${ARROW_LIB_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX})
-    set(ARROW_SHARED_IMPLIB ${ARROW_LIBS}/${ARROW_LIB_NAME}.lib)
-  endif ()
-endif()
-
-if (ARROW_FOUND)
-  if (NOT Arrow_FIND_QUIETLY)
-    message(STATUS "Arrow include path: ${ARROW_INCLUDE_DIR}")
-    if (PARQUET_MINIMAL_DEPENDENCY)
-      message(STATUS "Found the Arrow header: ${ARROW_HEADER}")
-    else ()
-      message(STATUS "Found the Arrow library: ${ARROW_LIB_PATH}")
-    endif ()
-  endif ()
-else()
-  if (NOT Arrow_FIND_QUIETLY)
-    set(ARROW_ERR_MSG "Could not find the Arrow library. Looked for headers")
-    set(ARROW_ERR_MSG "${ARROW_ERR_MSG} in ${ARROW_SEARCH_HEADER_PATHS}, and for libs")
-    set(ARROW_ERR_MSG "${ARROW_ERR_MSG} in ${ARROW_SEARCH_LIB_PATH}")
-    if (Arrow_FIND_REQUIRED)
-      message(FATAL_ERROR "${ARROW_ERR_MSG}")
-    else (Arrow_FIND_REQUIRED)
-      message(STATUS "${ARROW_ERR_MSG}")
-    endif (Arrow_FIND_REQUIRED)
-  endif ()
-endif()
-
-mark_as_advanced(
-  ARROW_FOUND
-  ARROW_INCLUDE_DIR
-  ARROW_STATIC_LIB
-  ARROW_SHARED_LIB
-)
diff --git a/cmake_modules/FindBrotli.cmake b/cmake_modules/FindBrotli.cmake
deleted file mode 100644
index f2e714c..0000000
--- a/cmake_modules/FindBrotli.cmake
+++ /dev/null
@@ -1,116 +0,0 @@
-#
-# 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.
-#
-# Tries to find Brotli headers and libraries.
-#
-# Usage of this module as follows:
-#
-#  find_package(Brotli)
-#
-# Variables used by this module, they can change the default behaviour and need
-# to be set before calling find_package:
-#
-#  Brotli_HOME - When set, this path is inspected instead of standard library
-#                locations as the root of the Brotli installation.
-#                The environment variable BROTLI_HOME overrides this veriable.
-#
-# This module defines
-#  BROTLI_INCLUDE_DIR, directory containing headers
-#  BROTLI_LIBS, directory containing brotli libraries
-#  BROTLI_STATIC_LIB, path to libbrotli.a
-#  BROTLI_SHARED_LIB, path to libbrotli's shared library
-#  BROTLI_FOUND, whether brotli has been found
-
-if( NOT "${BROTLI_HOME}" STREQUAL "")
-    file( TO_CMAKE_PATH "${BROTLI_HOME}" _native_path )
-    list( APPEND _brotli_roots ${_native_path} )
-elseif ( Brotli_HOME )
-    list( APPEND _brotli_roots ${Brotli_HOME} )
-endif()
-
-find_path( BROTLI_INCLUDE_DIR NAMES brotli/decode.h
-  PATHS ${_brotli_roots}
-  NO_DEFAULT_PATH
-  PATH_SUFFIXES "include" )
-
-find_library( BROTLI_LIBRARY_ENC NAMES libbrotlienc.a brotlienc
-  PATHS ${_brotli_roots}
-  NO_DEFAULT_PATH
-  PATH_SUFFIXES "lib/${CMAKE_LIBRARY_ARCHITECTURE}" "lib" )
-
-find_library( BROTLI_LIBRARY_DEC NAMES libbrotlidec.a brotlidec
-  PATHS ${_brotli_roots}
-  NO_DEFAULT_PATH
-  PATH_SUFFIXES "lib/${CMAKE_LIBRARY_ARCHITECTURE}" "lib" )
-
-find_library( BROTLI_LIBRARY_COMMON NAMES libbrotlicommon.a brotlicommon
-  PATHS ${_brotli_roots}
-  NO_DEFAULT_PATH
-  PATH_SUFFIXES "lib/${CMAKE_LIBRARY_ARCHITECTURE}" "lib" )
-
-set(BROTLI_LIBRARIES ${BROTLI_LIBRARY_ENC} ${BROTLI_LIBRARY_DEC}
-    ${BROTLI_LIBRARY_COMMON})
-
-if (BROTLI_INCLUDE_DIR AND (PARQUET_MINIMAL_DEPENDENCY OR BROTLI_LIBRARIES))
-  set(BROTLI_FOUND TRUE)
-  get_filename_component( BROTLI_LIBS ${BROTLI_LIBRARY_ENC} PATH )
-  set(BROTLI_LIB_NAME brotli)
-  if (MSVC AND NOT BROTLI_MSVC_STATIC_LIB_SUFFIX)
-    set(BROTLI_MSVC_STATIC_LIB_SUFFIX _static)
-  endif()
-  set(BROTLI_STATIC_LIB
-      ${BROTLI_LIBS}/${CMAKE_STATIC_LIBRARY_PREFIX}${BROTLI_LIB_NAME}enc${BROTLI_MSVC_STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}
-      ${BROTLI_LIBS}/${CMAKE_STATIC_LIBRARY_PREFIX}${BROTLI_LIB_NAME}dec${BROTLI_MSVC_STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}
-      ${BROTLI_LIBS}/${CMAKE_STATIC_LIBRARY_PREFIX}${BROTLI_LIB_NAME}common${BROTLI_MSVC_STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX})
-  set(BROTLI_STATIC_LIBRARY_ENC ${BROTLI_LIBS}/${CMAKE_STATIC_LIBRARY_PREFIX}${BROTLI_LIB_NAME}enc${BROTLI_MSVC_STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX})
-  set(BROTLI_STATIC_LIBRARY_DEC ${BROTLI_LIBS}/${CMAKE_STATIC_LIBRARY_PREFIX}${BROTLI_LIB_NAME}dec${BROTLI_MSVC_STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX})
-  set(BROTLI_STATIC_LIBRARY_COMMON ${BROTLI_LIBS}/${CMAKE_STATIC_LIBRARY_PREFIX}${BROTLI_LIB_NAME}common${BROTLI_MSVC_STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX})
-  set(BROTLI_SHARED_LIB
-      ${BROTLI_LIBS}/${CMAKE_SHARED_LIBRARY_PREFIX}${BROTLI_LIB_NAME}enc${CMAKE_SHARED_LIBRARY_SUFFIX}
-      ${BROTLI_LIBS}/${CMAKE_SHARED_LIBRARY_PREFIX}${BROTLI_LIB_NAME}dec${CMAKE_SHARED_LIBRARY_SUFFIX}
-      ${BROTLI_LIBS}/${CMAKE_SHARED_LIBRARY_PREFIX}${BROTLI_LIB_NAME}common${CMAKE_SHARED_LIBRARY_SUFFIX})
-else ()
-  set(BROTLI_FOUND FALSE)
-endif ()
-
-if (BROTLI_FOUND)
-  if (NOT Brotli_FIND_QUIETLY)
-    if (PARQUET_MINIMAL_DEPENDENCY)
-      message(STATUS "Found the Brotli headers: ${BROTLI_INCLUDE_DIR}")
-    else ()
-      message(STATUS "Found the Brotli library: ${BROTLI_LIBRARIES}")
-    endif ()
-  endif ()
-else ()
-  if (NOT Brotli_FIND_QUIETLY)
-    set(BROTLI_ERR_MSG "Could not find the Brotli library. Looked in ")
-    if ( _brotli_roots )
-      set(BROTLI_ERR_MSG "${BROTLI_ERR_MSG} in ${_brotli_roots}.")
-    else ()
-      set(BROTLI_ERR_MSG "${BROTLI_ERR_MSG} system search paths.")
-    endif ()
-    if (Brotli_FIND_REQUIRED)
-      message(FATAL_ERROR "${BROTLI_ERR_MSG}")
-    else (Brotli_FIND_REQUIRED)
-      message(STATUS "${BROTLI_ERR_MSG}")
-    endif (Brotli_FIND_REQUIRED)
-  endif ()
-endif ()
-
-mark_as_advanced(
-  BROTLI_INCLUDE_DIR
-  BROTLI_LIBS
-  BROTLI_LIBRARIES
-  BROTLI_STATIC_LIB
-  BROTLI_SHARED_LIB
-)
diff --git a/cmake_modules/FindClangTools.cmake b/cmake_modules/FindClangTools.cmake
deleted file mode 100644
index 56e2dd7..0000000
--- a/cmake_modules/FindClangTools.cmake
+++ /dev/null
@@ -1,118 +0,0 @@
-#
-# 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.
-#
-# Tries to find the clang-tidy and clang-format modules
-#
-# Usage of this module as follows:
-#
-#  find_package(ClangTools)
-#
-# Variables used by this module, they can change the default behaviour and need
-# to be set before calling find_package:
-#
-#  ClangToolsBin_HOME -
-#   When set, this path is inspected instead of standard library binary locations
-#   to find clang-tidy and clang-format
-#
-# This module defines
-#  CLANG_TIDY_BIN, The  path to the clang tidy binary
-#  CLANG_TIDY_FOUND, Whether clang tidy was found
-#  CLANG_FORMAT_BIN, The path to the clang format binary
-#  CLANG_TIDY_FOUND, Whether clang format was found
-
-if (DEFINED ENV{HOMEBREW_PREFIX})
-  set(HOMEBREW_PREFIX "${ENV{HOMEBREW_PREFIX}")
-else()
-  set(HOMEBREW_PREFIX "/usr/local")
-endif()
-
-find_program(CLANG_TIDY_BIN
-  NAMES clang-tidy-4.0
-  clang-tidy-3.9
-  clang-tidy-3.8
-  clang-tidy-3.7
-  clang-tidy-3.6
-  clang-tidy
-  PATHS ${ClangTools_PATH} $ENV{CLANG_TOOLS_PATH} /usr/local/bin /usr/bin "${HOMEBREW_PREFIX}/bin"
-        NO_DEFAULT_PATH
-)
-
-if ( "${CLANG_TIDY_BIN}" STREQUAL "CLANG_TIDY_BIN-NOTFOUND" )
-  set(CLANG_TIDY_FOUND 0)
-  message("clang-tidy not found")
-else()
-  set(CLANG_TIDY_FOUND 1)
-  message("clang-tidy found at ${CLANG_TIDY_BIN}")
-endif()
-
-if (CLANG_FORMAT_VERSION)
-    find_program(CLANG_FORMAT_BIN
-      NAMES clang-format-${CLANG_FORMAT_VERSION}
-      PATHS
-            ${ClangTools_PATH}
-            $ENV{CLANG_TOOLS_PATH}
-            /usr/local/bin /usr/bin "${HOMEBREW_PREFIX}/bin"
-            NO_DEFAULT_PATH
-    )
-
-    # If not found yet, search alternative locations
-    if (("${CLANG_FORMAT_BIN}" STREQUAL "CLANG_FORMAT_BIN-NOTFOUND") AND APPLE)
-        # Homebrew ships older LLVM versions in /usr/local/opt/llvm@version/
-        STRING(REGEX REPLACE "^([0-9]+)\\.[0-9]+" "\\1" CLANG_FORMAT_MAJOR_VERSION "${CLANG_FORMAT_VERSION}")
-        STRING(REGEX REPLACE "^[0-9]+\\.([0-9]+)" "\\1" CLANG_FORMAT_MINOR_VERSION "${CLANG_FORMAT_VERSION}")
-        if ("${CLANG_FORMAT_MINOR_VERSION}" STREQUAL "0")
-            find_program(CLANG_FORMAT_BIN
-              NAMES clang-format
-              PATHS "${HOMEBREW_PREFIX}/opt/llvm@${CLANG_FORMAT_MAJOR_VERSION}/bin"
-                    NO_DEFAULT_PATH
-            )
-        else()
-            find_program(CLANG_FORMAT_BIN
-              NAMES clang-format
-              PATHS "${HOMEBREW_PREFIX}/opt/llvm@${CLANG_FORMAT_VERSION}/bin"
-                    NO_DEFAULT_PATH
-            )
-        endif()
-
-        if ("${CLANG_FORMAT_BIN}" STREQUAL "CLANG_FORMAT_BIN-NOTFOUND")
-          # binary was still not found, look into Cellar
-          file(GLOB CLANG_FORMAT_PATH "${HOMEBREW_PREFIX}/Cellar/llvm/${CLANG_FORMAT_VERSION}.*")
-          find_program(CLANG_FORMAT_BIN
-            NAMES clang-format
-            PATHS "${CLANG_FORMAT_PATH}/bin"
-                  NO_DEFAULT_PATH
-          )
-        endif()
-    endif()
-else()
-    find_program(CLANG_FORMAT_BIN
-      NAMES clang-format-6.0
-      clang-format-5.0
-      clang-format-4.0
-      clang-format-3.9
-      clang-format-3.8
-      clang-format-3.7
-      clang-format-3.6
-      clang-format
-      PATHS ${ClangTools_PATH} $ENV{CLANG_TOOLS_PATH} /usr/local/bin /usr/bin "${HOMEBREW_PREFIX}/bin"
-            NO_DEFAULT_PATH
-    )
-endif()
-
-if ( "${CLANG_FORMAT_BIN}" STREQUAL "CLANG_FORMAT_BIN-NOTFOUND" )
-  set(CLANG_FORMAT_FOUND 0)
-  message("clang-format not found")
-else()
-  set(CLANG_FORMAT_FOUND 1)
-  message("clang-format found at ${CLANG_FORMAT_BIN}")
-endif()
diff --git a/cmake_modules/FindGBenchmark.cmake b/cmake_modules/FindGBenchmark.cmake
deleted file mode 100644
index 3e46a60..0000000
--- a/cmake_modules/FindGBenchmark.cmake
+++ /dev/null
@@ -1,88 +0,0 @@
-#
-# 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.
-#
-# Tries to find Google benchmark headers and libraries.
-#
-# Usage of this module as follows:
-#
-#  find_package(GBenchark)
-#
-# Variables used by this module, they can change the default behaviour and need
-# to be set before calling find_package:
-#
-#  GBenchmark_HOME - When set, this path is inspected instead of standard library
-#                    locations as the root of the benchark installation.
-#                    The environment variable GBENCHMARK_HOME overrides this veriable.
-#
-# This module defines
-#  GBENCHMARK_INCLUDE_DIR, directory containing benchmark header directory
-#  GBENCHMARK_LIBS, directory containing benchmark libraries
-#  GBENCHMARK_STATIC_LIB, path to libbenchmark.a
-#  GBENCHMARK_FOUND, whether gbenchmark has been found
-
-if( NOT "$ENV{GBENCHMARK_HOME}" STREQUAL "")
-    file( TO_CMAKE_PATH "$ENV{GBENCHMARK_HOME}" _native_path )
-    list( APPEND _gbenchmark_roots ${_native_path} )
-elseif ( GBenchmark_HOME )
-    list( APPEND _gbenchmark_roots ${GBenchmark_HOME} )
-endif()
-
-# Try the parameterized roots, if they exist
-if ( _gbenchmark_roots )
-    find_path( GBENCHMARK_INCLUDE_DIR NAMES benchmark/benchmark.h 
-        PATHS ${_gbenchmark_roots} NO_DEFAULT_PATH
-        PATH_SUFFIXES "include" )
-    find_library( GBENCHMARK_LIBRARIES NAMES benchmark
-        PATHS ${_gbenchmark_roots} NO_DEFAULT_PATH
-        PATH_SUFFIXES "lib" )
-else ()
-    find_path( GBENCHMARK_INCLUDE_DIR NAMES benchmark/benchmark.hh )
-    find_library( GBENCHMARK_LIBRARIES NAMES benchmark )
-endif ()
-
-
-if (GBENCHMARK_INCLUDE_DIR AND GBENCHMARK_LIBRARIES)
-  set(GBENCHMARK_FOUND TRUE)
-  get_filename_component( GBENCHMARK_LIBS ${GBENCHMARK_LIBRARIES} PATH )
-  set(GBENCHMARK_LIB_NAME libbenchmark)
-  set(GBENCHMARK_STATIC_LIB ${GBENCHMARK_LIBS}/${GBENCHMARK_LIB_NAME}.a)
-else ()
-  set(GBENCHMARK_FOUND FALSE)
-endif ()
-
-if (GBENCHMARK_FOUND)
-  if (NOT GBenchmark_FIND_QUIETLY)
-    message(STATUS "Found the GBenchmark library: ${GBENCHMARK_LIBRARIES}")
-  endif ()
-else ()
-  if (NOT GBenchmark_FIND_QUIETLY)
-    set(GBENCHMARK_ERR_MSG "Could not find the GBenchmark library. Looked in ")
-    if ( _gbenchmark_roots )
-      set(GBENCHMARK_ERR_MSG "${GBENCHMARK_ERR_MSG} in ${_gbenchmark_roots}.")
-    else ()
-      set(GBENCHMARK_ERR_MSG "${GBENCHMARK_ERR_MSG} system search paths.")
-    endif ()
-    if (GBenchmark_FIND_REQUIRED)
-      message(FATAL_ERROR "${GBENCHMARK_ERR_MSG}")
-    else (GBenchmark_FIND_REQUIRED)
-      message(STATUS "${GBENCHMARK_ERR_MSG}")
-    endif (GBenchmark_FIND_REQUIRED)
-  endif ()
-endif ()
-
-mark_as_advanced(
-  GBENCHMARK_INCLUDE_DIR
-  GBENCHMARK_LIBS
-  GBENCHMARK_LIBRARIES
-  GBENCHMARK_STATIC_LIB
-)
diff --git a/cmake_modules/FindGTest.cmake b/cmake_modules/FindGTest.cmake
deleted file mode 100644
index c6ea16b..0000000
--- a/cmake_modules/FindGTest.cmake
+++ /dev/null
@@ -1,94 +0,0 @@
-#
-# 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.
-#
-# Tries to find GTest headers and libraries.
-#
-# Usage of this module as follows:
-#
-#  find_package(GTest)
-#
-# Variables used by this module, they can change the default behaviour and need
-# to be set before calling find_package:
-#
-#  GTest_HOME - When set, this path is inspected instead of standard library
-#                locations as the root of the GTest installation.
-#                The environment variable GTEST_HOME overrides this veriable.
-#
-# This module defines
-#  GTEST_INCLUDE_DIR, directory containing headers
-#  GTEST_LIBS, directory containing gtest libraries
-#  GTEST_STATIC_LIB, path to libgtest.a
-#  GTEST_MAIN_STATIC_LIB, path to libgtest_main.a
-#  GTEST_SHARED_LIB, path to libgtest's shared library
-#  GTEST_FOUND, whether gtest has been found
-
-if( NOT "$ENV{GTEST_HOME}" STREQUAL "")
-    file( TO_CMAKE_PATH "$ENV{GTEST_HOME}" _native_path )
-    list( APPEND _gtest_roots ${_native_path} )
-elseif ( GTest_HOME )
-    list( APPEND _gtest_roots ${GTest_HOME} )
-endif()
-
-# Try the parameterized roots, if they exist
-if ( _gtest_roots )
-    find_path( GTEST_INCLUDE_DIR NAMES gtest/gtest.h
-        PATHS ${_gtest_roots} NO_DEFAULT_PATH
-        PATH_SUFFIXES "include" )
-    find_library( GTEST_LIBRARIES NAMES gtest gtest_main
-        PATHS ${_gtest_roots} NO_DEFAULT_PATH
-        PATH_SUFFIXES "lib" )
-else ()
-    find_path( GTEST_INCLUDE_DIR NAMES gtest/gtest.h )
-    find_library( GTEST_LIBRARIES NAMES gtest )
-endif ()
-
-
-if (GTEST_INCLUDE_DIR AND GTEST_LIBRARIES)
-  set(GTEST_FOUND TRUE)
-  get_filename_component( GTEST_LIBS ${GTEST_LIBRARIES} PATH )
-  set(GTEST_LIB_NAME gtest)
-  set(GTEST_STATIC_LIB ${GTEST_LIBS}/${CMAKE_STATIC_LIBRARY_PREFIX}${GTEST_LIB_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX})
-  set(GTEST_MAIN_STATIC_LIB ${GTEST_LIBS}/${CMAKE_STATIC_LIBRARY_PREFIX}${GTEST_LIB_NAME}_main${CMAKE_STATIC_LIBRARY_SUFFIX})
-  set(GTEST_SHARED_LIB ${GTEST_LIBS}/${CMAKE_SHARED_LIBRARY_PREFIX}${GTEST_LIB_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX})
-else ()
-  set(GTEST_FOUND FALSE)
-endif ()
-
-if (GTEST_FOUND)
-  if (NOT GTest_FIND_QUIETLY)
-    message(STATUS "Found the GTest library: ${GTEST_LIBRARIES}")
-  endif ()
-else ()
-  if (NOT GTest_FIND_QUIETLY)
-    set(GTEST_ERR_MSG "Could not find the GTest library. Looked in ")
-    if ( _gtest_roots )
-      set(GTEST_ERR_MSG "${GTEST_ERR_MSG} in ${_gtest_roots}.")
-    else ()
-      set(GTEST_ERR_MSG "${GTEST_ERR_MSG} system search paths.")
-    endif ()
-    if (GTest_FIND_REQUIRED)
-      message(FATAL_ERROR "${GTEST_ERR_MSG}")
-    else (GTest_FIND_REQUIRED)
-      message(STATUS "${GTEST_ERR_MSG}")
-    endif (GTest_FIND_REQUIRED)
-  endif ()
-endif ()
-
-mark_as_advanced(
-  GTEST_INCLUDE_DIR
-  GTEST_LIBS
-  GTEST_LIBRARIES
-  GTEST_STATIC_LIB
-  GTEST_MAIN_STATIC_LIB
-  GTEST_SHARED_LIB
-)
diff --git a/cmake_modules/FindSnappy.cmake b/cmake_modules/FindSnappy.cmake
deleted file mode 100644
index 867963c..0000000
--- a/cmake_modules/FindSnappy.cmake
+++ /dev/null
@@ -1,94 +0,0 @@
-#
-# 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.
-#
-# Tries to find Snappy headers and libraries.
-#
-# Usage of this module as follows:
-#
-#  find_package(Snappy)
-#
-# Variables used by this module, they can change the default behaviour and need
-# to be set before calling find_package:
-#
-#  Snappy_HOME - When set, this path is inspected instead of standard library
-#                locations as the root of the Snappy installation.
-#                The environment variable SNAPPY_HOME overrides this variable.
-#
-# This module defines
-#  SNAPPY_INCLUDE_DIR, directory containing headers
-#  SNAPPY_LIBS, directory containing snappy libraries
-#  SNAPPY_STATIC_LIB, path to libsnappy.a
-#  SNAPPY_SHARED_LIB, path to libsnappy's shared library
-#  SNAPPY_FOUND, whether snappy has been found
-
-if( NOT "${SNAPPY_HOME}" STREQUAL "")
-    file( TO_CMAKE_PATH "${SNAPPY_HOME}" _native_path )
-    list( APPEND _snappy_roots ${_native_path} )
-elseif ( Snappy_HOME )
-    list( APPEND _snappy_roots ${Snappy_HOME} )
-endif()
-
-message(STATUS "SNAPPY_HOME: ${SNAPPY_HOME}")
-find_path(SNAPPY_INCLUDE_DIR snappy.h HINTS
-  ${_snappy_roots}
-  NO_DEFAULT_PATH
-  PATH_SUFFIXES "include")
-
-find_library( SNAPPY_LIBRARIES NAMES snappy PATHS
-  ${_snappy_roots}
-  NO_DEFAULT_PATH
-  PATH_SUFFIXES "lib")
-
-if (SNAPPY_INCLUDE_DIR AND (PARQUET_MINIMAL_DEPENDENCY OR SNAPPY_LIBRARIES))
-  set(SNAPPY_FOUND TRUE)
-  get_filename_component( SNAPPY_LIBS ${SNAPPY_LIBRARIES} PATH )
-  set(SNAPPY_HEADER_NAME snappy.h)
-  set(SNAPPY_HEADER ${SNAPPY_INCLUDE_DIR}/${SNAPPY_HEADER_NAME})
-  set(SNAPPY_LIB_NAME snappy)
-  set(SNAPPY_STATIC_LIB ${SNAPPY_LIBS}/${CMAKE_STATIC_LIBRARY_PREFIX}${SNAPPY_LIB_NAME}${SNAPPY_MSVC_STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX})
-  set(SNAPPY_SHARED_LIB ${SNAPPY_LIBS}/${CMAKE_SHARED_LIBRARY_PREFIX}${SNAPPY_LIB_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX})
-else ()
-  set(SNAPPY_FOUND FALSE)
-endif ()
-
-if (SNAPPY_FOUND)
-  if (NOT Snappy_FIND_QUIETLY)
-    if (PARQUET_MINIMAL_DEPENDENCY)
-      message(STATUS "Found the Snappy header: ${SNAPPY_HEADER}")
-    else ()
-      message(STATUS "Found the Snappy library: ${SNAPPY_LIBRARIES}")
-    endif ()
-  endif ()
-else ()
-  if (NOT Snappy_FIND_QUIETLY)
-    set(SNAPPY_ERR_MSG "Could not find the Snappy library. Looked in ")
-    if ( _snappy_roots )
-      set(SNAPPY_ERR_MSG "${SNAPPY_ERR_MSG} in ${_snappy_roots}.")
-    else ()
-      set(SNAPPY_ERR_MSG "${SNAPPY_ERR_MSG} system search paths.")
-    endif ()
-    if (Snappy_FIND_REQUIRED)
-      message(FATAL_ERROR "${SNAPPY_ERR_MSG}")
-    else (Snappy_FIND_REQUIRED)
-      message(STATUS "${SNAPPY_ERR_MSG}")
-    endif (Snappy_FIND_REQUIRED)
-  endif ()
-endif ()
-
-mark_as_advanced(
-  SNAPPY_INCLUDE_DIR
-  SNAPPY_LIBS
-  SNAPPY_LIBRARIES
-  SNAPPY_STATIC_LIB
-  SNAPPY_SHARED_LIB
-)
diff --git a/cmake_modules/FindThrift.cmake b/cmake_modules/FindThrift.cmake
deleted file mode 100644
index 25f5082..0000000
--- a/cmake_modules/FindThrift.cmake
+++ /dev/null
@@ -1,102 +0,0 @@
-# Copyright 2012 Cloudera Inc.
-#
-# 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.
-
-# - Find Thrift (a cross platform RPC lib/tool)
-#
-# Variables used by this module, they can change the default behaviour and need
-# to be set before calling find_package:
-#
-#  Thrift_HOME - When set, this path is inspected instead of standard library
-#                locations as the root of the Thrift installation.
-#                The environment variable THRIFT_HOME overrides this variable.
-#
-# This module defines
-#  THRIFT_VERSION, version string of ant if found
-#  THRIFT_INCLUDE_DIR, where to find THRIFT headers
-#  THRIFT_CONTRIB_DIR, where contrib thrift files (e.g. fb303.thrift) are installed
-#  THRIFT_STATIC_LIB, THRIFT static library
-#  THRIFT_FOUND, If false, do not try to use ant
-
-# prefer the thrift version supplied in THRIFT_HOME
-if( NOT "${THRIFT_HOME}" STREQUAL "")
-    file( TO_CMAKE_PATH "${THRIFT_HOME}" _native_path )
-    list( APPEND _thrift_roots ${_native_path} )
-elseif ( Thrift_HOME )
-    list( APPEND _thrift_roots ${Thrift_HOME} )
-endif()
-
-message(STATUS "THRIFT_HOME: ${THRIFT_HOME}")
-find_path(THRIFT_INCLUDE_DIR thrift/Thrift.h HINTS
-  ${_thrift_roots}
-  NO_DEFAULT_PATH
-  PATH_SUFFIXES "include"
-)
-
-find_path(THRIFT_CONTRIB_DIR share/fb303/if/fb303.thrift HINTS
-  ${_thrift_roots}
-  NO_DEFAULT_PATH
-)
-
-if (MSVC AND NOT THRIFT_MSVC_STATIC_LIB_SUFFIX)
-  set(THRIFT_MSVC_STATIC_LIB_SUFFIX md)
-endif()
-
-find_library(THRIFT_STATIC_LIB NAMES
-  ${CMAKE_STATIC_LIBRARY_PREFIX}thrift${THRIFT_MSVC_STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}
-  HINTS ${_thrift_roots}
-  NO_DEFAULT_PATH
-  PATH_SUFFIXES "lib/${CMAKE_LIBRARY_ARCHITECTURE}" "lib"
-)
-
-find_program(THRIFT_COMPILER thrift HINTS
-  ${_thrift_roots}
-  NO_DEFAULT_PATH
-  PATH_SUFFIXES "bin"
-)
-
-if (THRIFT_STATIC_LIB)
-  set(THRIFT_FOUND TRUE)
-  exec_program(${THRIFT_COMPILER}
-    ARGS -version OUTPUT_VARIABLE THRIFT_VERSION RETURN_VALUE THRIFT_RETURN)
-else ()
-  set(THRIFT_FOUND FALSE)
-endif ()
-
-if (THRIFT_FOUND)
-  if (NOT Thrift_FIND_QUIETLY)
-    message(STATUS "Thrift version: ${THRIFT_VERSION}")
-  endif ()
-else ()
-  if (NOT Thrift_FIND_QUIETLY)
-    set(THRIFT_ERR_MSG "Thrift compiler/libraries NOT found: ${THRIFT_RETURN}")
-    set(THRIFT_ERR_MSG "${THRIFT_ERR_MSG} (${THRIFT_INCLUDE_DIR}, ${THRIFT_STATIC_LIB}).")
-    if ( _thrift_roots )
-      set(THRIFT_ERR_MSG "${THRIFT_ERR_MSG} Looked in ${_thrift_roots}.")
-    else ()
-      set(THRIFT_ERR_MSG "${THRIFT_ERR_MSG} Looked in system search paths.")
-    endif ()
-    if ( Thrift_FIND_REQUIRED )
-      message(FATAL_ERROR "${THRIFT_ERR_MSG}")
-    else ()
-      message(STATUS "${THRIFT_ERR_MSG}")
-    endif ()
-  endif ()
-endif ()
-
-
-mark_as_advanced(
-  THRIFT_STATIC_LIB
-  THRIFT_COMPILER
-  THRIFT_INCLUDE_DIR
-)
diff --git a/cmake_modules/FindZLIB.cmake b/cmake_modules/FindZLIB.cmake
deleted file mode 100644
index 78b84f2..0000000
--- a/cmake_modules/FindZLIB.cmake
+++ /dev/null
@@ -1,105 +0,0 @@
-#
-# 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.
-#
-# Tries to find ZLIB headers and libraries.
-#
-# Usage of this module as follows:
-#
-#  find_package(ZLIB)
-#
-# Variables used by this module, they can change the default behaviour and need
-# to be set before calling find_package:
-#
-#  ZLIB_HOME - When set, this path is inspected instead of standard library
-#             locations as the root of the ZLIB installation.
-#             The environment variable ZLIB_HOME overrides this variable.
-#
-# - Find ZLIB (zlib.h, libz.a, libz.so, and libz.so.1)
-# This module defines
-#  ZLIB_INCLUDE_DIR, directory containing headers
-#  ZLIB_LIBS, directory containing zlib libraries
-#  ZLIB_STATIC_LIB, path to libz.a
-#  ZLIB_SHARED_LIB, path to libz's shared library
-#  ZLIB_FOUND, whether zlib has been found
-
-if( NOT "${ZLIB_HOME}" STREQUAL "")
-    file( TO_CMAKE_PATH "${ZLIB_HOME}" _native_path )
-    list( APPEND _zlib_roots ${_native_path} )
-elseif ( ZLIB_HOME )
-    list( APPEND _zlib_roots ${ZLIB_HOME} )
-endif()
-
-# Try the parameterized roots, if they exist
-if ( _zlib_roots )
-    find_path( ZLIB_INCLUDE_DIR NAMES zlib.h
-        PATHS ${_zlib_roots} NO_DEFAULT_PATH
-        PATH_SUFFIXES "include" )
-    find_library( ZLIB_LIBRARIES NAMES libz.a zlib
-        PATHS ${_zlib_roots} NO_DEFAULT_PATH
-        PATH_SUFFIXES "lib" )
-else ()
-    find_path( ZLIB_INCLUDE_DIR NAMES zlib.h )
-    # Only look for the static library
-    find_library( ZLIB_LIBRARIES NAMES libz.a zlib )
-endif ()
-
-
-if (ZLIB_INCLUDE_DIR AND (PARQUET_MINIMAL_DEPENDENCY OR ZLIB_LIBRARIES))
-  set(ZLIB_FOUND TRUE)
-  get_filename_component( ZLIB_LIBS ${ZLIB_LIBRARIES} PATH )
-  set(ZLIB_HEADER_NAME zlib.h)
-  set(ZLIB_HEADER ${ZLIB_INCLUDE_DIR}/${ZLIB_HEADER_NAME})
-  set(ZLIB_LIB_NAME z)
-  if (MSVC)
-    if (NOT ZLIB_MSVC_STATIC_LIB_SUFFIX)
-      set(ZLIB_MSVC_STATIC_LIB_SUFFIX libstatic)
-    endif()
-    set(ZLIB_MSVC_SHARED_LIB_SUFFIX lib)
-  endif()
-  set(ZLIB_STATIC_LIB ${ZLIB_LIBS}/${CMAKE_STATIC_LIBRARY_PREFIX}${ZLIB_LIB_NAME}${ZLIB_MSVC_STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX})
-  set(ZLIB_SHARED_LIB ${ZLIB_LIBS}/${CMAKE_SHARED_LIBRARY_PREFIX}${ZLIB_LIB_NAME}${ZLIB_MSVC_SHARED_LIB_SUFFIX}${CMAKE_SHARED_LIBRARY_SUFFIX})
-else ()
-  set(ZLIB_FOUND FALSE)
-endif ()
-
-if (ZLIB_FOUND)
-  if (NOT ZLIB_FIND_QUIETLY)
-    if (PARQUET_MINIMAL_DEPENDENCY)
-      message(STATUS "Found the ZLIB header: ${ZLIB_HEADER}")
-    else()
-      message(STATUS "Found the ZLIB library: ${ZLIB_LIBRARIES}")
-    endif ()
-  endif ()
-else ()
-  if (NOT ZLIB_FIND_QUIETLY)
-    set(ZLIB_ERR_MSG "Could not find the ZLIB library. Looked in ")
-    if ( _zlib_roots )
-      set(ZLIB_ERR_MSG "${ZLIB_ERR_MSG} in ${_zlib_roots}.")
-    else ()
-      set(ZLIB_ERR_MSG "${ZLIB_ERR_MSG} system search paths.")
-    endif ()
-    if (ZLIB_FIND_REQUIRED)
-      message(FATAL_ERROR "${ZLIB_ERR_MSG}")
-    else (ZLIB_FIND_REQUIRED)
-      message(STATUS "${ZLIB_ERR_MSG}")
-    endif (ZLIB_FIND_REQUIRED)
-  endif ()
-endif ()
-
-mark_as_advanced(
-  ZLIB_INCLUDE_DIR
-  ZLIB_LIBS
-  ZLIB_LIBRARIES
-  ZLIB_STATIC_LIB
-  ZLIB_SHARED_LIB
-)
diff --git a/cmake_modules/SetupCxxFlags.cmake b/cmake_modules/SetupCxxFlags.cmake
deleted file mode 100644
index 0029501..0000000
--- a/cmake_modules/SetupCxxFlags.cmake
+++ /dev/null
@@ -1,248 +0,0 @@
-# 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.
-
-# Check if the target architecture and compiler supports some special
-# instruction sets that would boost performance.
-include(CheckCXXCompilerFlag)
-# x86/amd64 compiler flags
-CHECK_CXX_COMPILER_FLAG("-msse3" CXX_SUPPORTS_SSE3)
-# power compiler flags
-CHECK_CXX_COMPILER_FLAG("-maltivec" CXX_SUPPORTS_ALTIVEC)
-
-# compiler flags that are common across debug/release builds
-
-if (MSVC)
-  # TODO(wesm): Change usages of C runtime functions that MSVC says are
-  # insecure, like std::getenv
-  add_definitions(-D_CRT_SECURE_NO_WARNINGS)
-
-  # Use __declspec(dllexport) during library build, other users of the Parquet
-  # headers will see dllimport
-  add_definitions(-DPARQUET_EXPORTING)
-
-  if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
-    # clang-cl
-    set(CXX_COMMON_FLAGS "-EHsc")
-  elseif(${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 19)
-    message(FATAL_ERROR "Only MSVC 2015 (Version 19.0) and later are supported
-    by Parquet. Found version ${CMAKE_CXX_COMPILER_VERSION}.")
-  else()
-    # Fix annoying D9025 warning
-    string(REPLACE "/W3" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
-
-    # Set desired warning level (e.g. set /W4 for more warnings)
-    set(CXX_COMMON_FLAGS "/W3")
-  endif()
-
-  if (PARQUET_USE_STATIC_CRT)
-    foreach (c_flag CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_DEBUG
-                    CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO
-                    CMAKE_C_FLAGS CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_DEBUG
-                    CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
-      string(REPLACE "/MD" "-MT" ${c_flag} "${${c_flag}}")
-    endforeach()
-  endif()
-else()
-  # Common flags set below with warning level
-  set(CXX_COMMON_FLAGS "")
-endif()
-
-# Build warning level (CHECKIN, EVERYTHING, etc.)
-
-# if no build warning level is specified, default to development warning level
-if (NOT PARQUET_BUILD_WARNING_LEVEL)
-  set(PARQUET_BUILD_WARNING_LEVEL Production)
-endif(NOT PARQUET_BUILD_WARNING_LEVEL)
-
-string(TOUPPER ${PARQUET_BUILD_WARNING_LEVEL} UPPERCASE_BUILD_WARNING_LEVEL)
-
-if ("${UPPERCASE_BUILD_WARNING_LEVEL}" STREQUAL "CHECKIN")
-  # Pre-checkin builds
-  if ("${COMPILER_FAMILY}" STREQUAL "msvc")
-    string(REPLACE "/W3" "" CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS}")
-    set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} /W3")
-    # Treat all compiler warnings as errors
-    set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} /WX")
-  elseif ("${COMPILER_FAMILY}" STREQUAL "clang")
-    set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -Weverything -Wno-c++98-compat \
--Wno-c++98-compat-pedantic -Wno-deprecated -Wno-deprecated-declarations \
--Wno-weak-vtables -Wno-padded -Wno-comma -Wno-unused-parameter -Wno-undef \
--Wno-shadow -Wno-switch-enum -Wno-exit-time-destructors \
--Wno-global-constructors -Wno-weak-template-vtables -Wno-undefined-reinterpret-cast \
--Wno-implicit-fallthrough -Wno-unreachable-code-return \
--Wno-documentation-deprecated-sync \
--Wno-float-equal -Wno-missing-prototypes \
--Wno-old-style-cast -Wno-covered-switch-default \
--Wno-format-nonliteral -Wno-missing-noreturn \
--Wno-cast-align -Wno-vla-extension -Wno-shift-sign-overflow \
--Wno-used-but-marked-unused -Wno-missing-variable-declarations \
--Wno-gnu-zero-variadic-macro-arguments -Wconversion -Wno-sign-conversion \
--Wno-disabled-macro-expansion -Wno-shorten-64-to-32")
-
-    message(STATUS "Clang version: ${COMPILER_VERSION}")
-
-    # Version numbers where warnings are introduced
-    if ("${COMPILER_VERSION}" VERSION_GREATER "3.3")
-      set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -Wno-gnu-folding-constant")
-    endif()
-    if ("${COMPILER_VERSION}" VERSION_GREATER "3.6")
-      set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -Wno-reserved-id-macro")
-      set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -Wno-range-loop-analysis")
-    endif()
-    if ("${COMPILER_VERSION}" VERSION_GREATER "3.7")
-      set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -Wno-double-promotion")
-    endif()
-    if ("${COMPILER_VERSION}" VERSION_GREATER "3.8")
-      set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -Wno-undefined-func-template")
-    endif()
-
-    if ("${COMPILER_VERSION}" VERSION_GREATER "4.0")
-      set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -Wno-unused-template \
--Wno-zero-as-null-pointer-constant")
-    endif()
-
-    # Treat all compiler warnings as errors
-    set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -Wno-unknown-warning-option -Werror")
-  elseif ("${COMPILER_FAMILY}" STREQUAL "gcc")
-    set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -Wall \
--Wno-deprecated-declarations -Wconversion -Wno-sign-conversion")
-    # Treat all compiler warnings as errors
-    set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -Werror")
-  else()
-    message(FATAL_ERROR "Unknown compiler. Version info:\n${COMPILER_VERSION_FULL}")
-  endif()
-elseif ("${UPPERCASE_BUILD_WARNING_LEVEL}" STREQUAL "EVERYTHING")
-  # Pedantic builds for fixing warnings
-  if ("${COMPILER_FAMILY}" STREQUAL "msvc")
-    string(REPLACE "/W3" "" CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS}")
-    set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} /Wall")
-    # https://docs.microsoft.com/en-us/cpp/build/reference/compiler-option-warning-level
-    # /wdnnnn disables a warning where "nnnn" is a warning number
-    # Treat all compiler warnings as errors
-    set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS}  /WX")
-  elseif ("${COMPILER_FAMILY}" STREQUAL "clang")
-    set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic")
-    # Treat all compiler warnings as errors
-    set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -Werror")
-  elseif ("${COMPILER_FAMILY}" STREQUAL "gcc")
-    set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -Wall -Wpedantic -Wextra -Wno-unused-parameter")
-    # Treat all compiler warnings as errors
-    set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -Werror")
-  else()
-    message(FATAL_ERROR "Unknown compiler. Version info:\n${COMPILER_VERSION_FULL}")
-  endif()
-else()
-  # Production builds (warning are not treated as errors)
-  if ("${COMPILER_FAMILY}" STREQUAL "msvc")
-    # https://docs.microsoft.com/en-us/cpp/build/reference/compiler-option-warning-level
-    # TODO: Enable /Wall and disable individual warnings until build compiles without errors
-    # /wdnnnn disables a warning where "nnnn" is a warning number
-    string(REPLACE "/W3" "" CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS}")
-    set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} /W3")
-  elseif ("${COMPILER_FAMILY}" STREQUAL "clang")
-    set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -Wall")
-  elseif ("${COMPILER_FAMILY}" STREQUAL "gcc")
-    set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -Wall")
-  else()
-    message(FATAL_ERROR "Unknown compiler. Version info:\n${COMPILER_VERSION_FULL}")
-  endif()
-endif()
-
-# if build warning flags is set, add to CXX_COMMON_FLAGS
-if (BUILD_WARNING_FLAGS)
-  # Use BUILD_WARNING_FLAGS with BUILD_WARNING_LEVEL=everything to disable
-  # warnings (use with Clang's -Weverything flag to find potential errors)
-  set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} ${BUILD_WARNING_FLAGS}")
-endif(BUILD_WARNING_FLAGS)
-
-if ("${COMPILER_FAMILY}" STREQUAL "clang")
-  # Using Clang with ccache causes a bunch of spurious warnings that are
-  # purportedly fixed in the next version of ccache. See the following for details:
-  #
-  #   http://petereisentraut.blogspot.com/2011/05/ccache-and-clang.html
-  #   http://petereisentraut.blogspot.com/2011/09/ccache-and-clang-part-2.html
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Qunused-arguments")
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CLANG_OPTIONS}")
-endif()
-
-if (NOT ("${COMPILER_FAMILY}" STREQUAL "msvc"))
-set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -std=c++11")
-endif()
-
-if ("${COMPILER_FAMILY}" STREQUAL "msvc")
-  # Support large object code
-  set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} /bigobj")
-
-  # MSVC version of -Wno-deprecated
-  set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} /wd4996")
-endif()
-
-if (PARQUET_USE_SSE)
-  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
-  add_definitions(-DPARQUET_USE_SSE)
-endif()
-
-if (APPLE)
-  # Depending on the default OSX_DEPLOYMENT_TARGET (< 10.9), libstdc++ may be
-  # the default standard library which does not support C++11. libc++ is the
-  # default from 10.9 onward.
-  set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -stdlib=libc++")
-endif()
-
-# compiler flags for different build types (run 'cmake -DCMAKE_BUILD_TYPE=<type> .')
-# For all builds:
-# For CMAKE_BUILD_TYPE=Debug
-#   -ggdb: Enable gdb debugging
-# For CMAKE_BUILD_TYPE=FastDebug
-#   Same as DEBUG, except with some optimizations on.
-# For CMAKE_BUILD_TYPE=Release
-#   -O3: Enable all compiler optimizations
-#   Debug symbols are stripped for reduced binary size. Add
-#   -DPARQUET_CXXFLAGS="-g" to add them
-if (NOT MSVC)
-  set(CXX_FLAGS_DEBUG "-ggdb -O0")
-  set(CXX_FLAGS_FASTDEBUG "-ggdb -O1")
-  set(CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
-endif()
-
-set(CXX_FLAGS_PROFILE_GEN "${CXX_FLAGS_RELEASE} -fprofile-generate")
-set(CXX_FLAGS_PROFILE_BUILD "${CXX_FLAGS_RELEASE} -fprofile-use")
-
-# if no build build type is specified, default to debug builds
-if (NOT CMAKE_BUILD_TYPE)
-  set(CMAKE_BUILD_TYPE Debug)
-endif(NOT CMAKE_BUILD_TYPE)
-
-string (TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE)
-
-# Set compile flags based on the build type.
-message("Configured for ${CMAKE_BUILD_TYPE} build (set with cmake -DCMAKE_BUILD_TYPE={release,debug,...})")
-if ("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG")
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_FLAGS_DEBUG}")
-elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "FASTDEBUG")
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_FLAGS_FASTDEBUG}")
-elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE")
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_FLAGS_RELEASE}")
-elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "PROFILE_GEN")
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_FLAGS_PROFILE_GEN}")
-elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "PROFILE_BUILD")
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_FLAGS_PROFILE_BUILD}")
-else()
-  message(FATAL_ERROR "Unknown build type: ${CMAKE_BUILD_TYPE}")
-endif ()
-
-message(STATUS "Build Type: ${CMAKE_BUILD_TYPE}")
diff --git a/cmake_modules/SnappyCMakeLists.txt b/cmake_modules/SnappyCMakeLists.txt
deleted file mode 100644
index 0348eb1..0000000
--- a/cmake_modules/SnappyCMakeLists.txt
+++ /dev/null
@@ -1,99 +0,0 @@
-# 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.
-#
-# Originally import from the Snappy repository with the following license:
-#
-# Copyright 2008 Google Inc. All Rights Reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
-PROJECT(snappy)
-
-INCLUDE(CheckIncludeFiles)
-INCLUDE(CMakePackageConfigHelpers)
-
-CHECK_INCLUDE_FILES("stdint.h" HAVE_STDINT_H)
-CHECK_INCLUDE_FILES("stddef.h" HAVE_STDDEF_H)
-CHECK_INCLUDE_FILES("sys/uio.h" HAVE_SYS_UIO_H)
-
-if (NOT HAVE_SYS_UIO_H)
-  set(HAVE_SYS_UIO_H 0)
-endif()
-
-if (NOT HAVE_STDINT_H)
-  set(HAVE_STDINT_H 0)
-endif()
-
-if (NOT HAVE_STDDEF_H)
-  set(HAVE_STDDEF_H 0)
-endif()
-
-set(ac_cv_have_stdint_h ${HAVE_STDINT_H})
-set(ac_cv_have_stddef_h ${HAVE_STDDEF_H})
-set(ac_cv_have_sys_uio_h ${HAVE_SYS_UIO_H})
-CONFIGURE_FILE(${snappy_SOURCE_DIR}/snappy-stubs-public.h.in
-               snappy-stubs-public.h)
-
-if (WIN32)
-  ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS)
-endif()
-
-set(SNAPPY_SRCS snappy.cc
-  snappy-c.cc
-  snappy-stubs-internal.cc
-  snappy-sinksource.cc
-  snappy.h
-  snappy-c.h
-  snappy-sinksource.h
-  snappy-stubs-public.h)
-
-add_library(snappy SHARED ${SNAPPY_SRCS})
-add_library(snappystatic STATIC ${SNAPPY_SRCS})
-
-TARGET_COMPILE_DEFINITIONS(snappy PRIVATE -DHAVE_CONFIG_H)
-TARGET_COMPILE_DEFINITIONS(snappystatic PRIVATE -DHAVE_CONFIG_H)
-
-install(FILES snappy.h
-  snappy-c.h
-  snappy-sinksource.h
-  ${snappy_BINARY_DIR}/snappy-stubs-public.h
-  DESTINATION include)
-
-install(TARGETS snappy snappystatic
-  RUNTIME DESTINATION bin
-  LIBRARY DESTINATION lib
-  ARCHIVE DESTINATION lib)
diff --git a/cmake_modules/SnappyConfig.h b/cmake_modules/SnappyConfig.h
deleted file mode 100644
index 5764deb..0000000
--- a/cmake_modules/SnappyConfig.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// 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.
-//
-// Originally import from the Snappy repository with the following license:
-//
-// Copyright 2008 Google Inc. All Rights Reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef SNAPPY_CONFIG_H
-#define SNAPPY_CONFIG_H 1
-
-#if defined(_MSC_VER) && (_MSC_VER <= 1900)
-typedef __int64 ssize_t;
-#endif
-
-#endif
diff --git a/cmake_modules/ThirdpartyToolchain.cmake b/cmake_modules/ThirdpartyToolchain.cmake
deleted file mode 100644
index 1934742..0000000
--- a/cmake_modules/ThirdpartyToolchain.cmake
+++ /dev/null
@@ -1,419 +0,0 @@
-# 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.
-
-set(GTEST_VERSION "1.8.0")
-set(GBENCHMARK_VERSION "1.1.0")
-set(THRIFT_VENDOR_VERSION "0.11.0")
-
-string(TOUPPER ${CMAKE_BUILD_TYPE} UPPERCASE_BUILD_TYPE)
-
-set(EP_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${UPPERCASE_BUILD_TYPE}}")
-set(EP_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${UPPERCASE_BUILD_TYPE}}")
-
-if (NOT MSVC)
-  # Set -fPIC on all external projects
-  set(EP_CXX_FLAGS "${EP_CXX_FLAGS} -fPIC")
-  set(EP_C_FLAGS "${EP_C_FLAGS} -fPIC")
-endif()
-
-if (NOT PARQUET_VERBOSE_THIRDPARTY_BUILD)
-  set(EP_LOG_OPTIONS
-    LOG_CONFIGURE 1
-    LOG_BUILD 1
-    LOG_INSTALL 1
-    LOG_DOWNLOAD 1)
-  set(Boost_DEBUG FALSE)
-else()
-  set(EP_LOG_OPTIONS)
-  set(Boost_DEBUG TRUE)
-endif()
-
-# ----------------------------------------------------------------------
-# Configure toolchain with environment variables, if the exist
-
-if (NOT "$ENV{PARQUET_BUILD_TOOLCHAIN}" STREQUAL "")
-  set(THRIFT_HOME "$ENV{PARQUET_BUILD_TOOLCHAIN}")
-  set(ARROW_HOME "$ENV{PARQUET_BUILD_TOOLCHAIN}")
-
-  if (NOT DEFINED ENV{BOOST_ROOT})
-    # Since we have to set this in the environment, we check whether
-    # $BOOST_ROOT is defined inside here
-    set(ENV{BOOST_ROOT} "$ENV{PARQUET_BUILD_TOOLCHAIN}")
-  endif()
-endif()
-
-if (DEFINED ENV{THRIFT_HOME})
-  set(THRIFT_HOME "$ENV{THRIFT_HOME}")
-endif()
-
-# ----------------------------------------------------------------------
-# Boost
-
-# find boost headers and libs
-set(Boost_USE_MULTITHREADED ON)
-if (MSVC AND PARQUET_USE_STATIC_CRT)
-  set(Boost_USE_STATIC_RUNTIME ON)
-endif()
-if (MSVC)
-  # disable autolinking in boost
-  add_definitions(-DBOOST_ALL_NO_LIB)
-endif()
-if (PARQUET_BOOST_USE_SHARED)
-  # Find shared Boost libraries.
-  set(Boost_USE_STATIC_LIBS OFF)
-
-  if (MSVC)
-    # force all boost libraries to dynamic link
-    add_definitions(-DBOOST_ALL_DYN_LINK)
-    find_package(Boost COMPONENTS regex system REQUIRED)
-  else()
-    find_package(Boost COMPONENTS regex REQUIRED)
-  endif()
-
-  if ("${UPPERCASE_BUILD_TYPE}" STREQUAL "DEBUG")
-    set(BOOST_SHARED_REGEX_LIBRARY ${Boost_REGEX_LIBRARY_DEBUG})
-    if (MSVC)
-      set(BOOST_SHARED_SYSTEM_LIBRARY ${Boost_SYSTEM_LIBRARY_DEBUG})
-    endif()
-  else()
-    set(BOOST_SHARED_REGEX_LIBRARY ${Boost_REGEX_LIBRARY_RELEASE})
-    if (MSVC)
-      set(BOOST_SHARED_SYSTEM_LIBRARY ${Boost_SYSTEM_LIBRARY_RELEASE})
-    endif()
-  endif()
-else()
-  # Find static Boost libraries.
-  set(Boost_USE_STATIC_LIBS ON)
-  if (MSVC)
-    find_package(Boost COMPONENTS regex system filesystem REQUIRED)
-  else()
-    find_package(Boost COMPONENTS regex REQUIRED)
-  endif()
-  if ("${UPPERCASE_BUILD_TYPE}" STREQUAL "DEBUG")
-    set(BOOST_STATIC_REGEX_LIBRARY ${Boost_REGEX_LIBRARY_DEBUG})
-    if (MSVC)
-      set(BOOST_STATIC_SYSTEM_LIBRARY ${Boost_SYSTEM_LIBRARY_DEBUG})
-      set(BOOST_STATIC_FILESYSTEM_LIBRARY ${Boost_FILESYSTEM_LIBRARY_DEBUG})
-    endif()
-  else()
-    set(BOOST_STATIC_REGEX_LIBRARY ${Boost_REGEX_LIBRARY_RELEASE})
-    if (MSVC)
-      set(BOOST_STATIC_SYSTEM_LIBRARY ${Boost_SYSTEM_LIBRARY_RELEASE})
-      set(BOOST_STATIC_FILESYSTEM_LIBRARY ${Boost_FILESYSTEM_LIBRARY_RELEASE})
-    endif()
-  endif()
-endif()
-
-message(STATUS "Boost include dir: " ${Boost_INCLUDE_DIRS})
-message(STATUS "Boost libraries: " ${Boost_LIBRARIES})
-if (PARQUET_BOOST_USE_SHARED)
-  add_library(boost_shared_regex SHARED IMPORTED)
-  if (MSVC)
-    set_target_properties(boost_shared_regex
-                          PROPERTIES IMPORTED_IMPLIB "${BOOST_SHARED_REGEX_LIBRARY}")
-  else()
-    set_target_properties(boost_shared_regex
-                          PROPERTIES IMPORTED_LOCATION "${BOOST_SHARED_REGEX_LIBRARY}")
-  endif()
-  if (MSVC)
-    add_library(boost_shared_system SHARED IMPORTED)
-    set_target_properties(boost_shared_system
-                          PROPERTIES IMPORTED_IMPLIB "${BOOST_SHARED_SYSTEM_LIBRARY}")
-  endif()
-else()
-  add_library(boost_static_regex STATIC IMPORTED)
-  set_target_properties(boost_static_regex PROPERTIES IMPORTED_LOCATION ${BOOST_STATIC_REGEX_LIBRARY})
-  if (MSVC)
-    add_library(boost_static_system STATIC IMPORTED)
-    set_target_properties(boost_static_system PROPERTIES IMPORTED_LOCATION ${BOOST_STATIC_SYSTEM_LIBRARY})
-    add_library(boost_static_filesystem STATIC IMPORTED)
-    set_target_properties(boost_static_filesystem PROPERTIES IMPORTED_LOCATION ${BOOST_STATIC_FILESYSTEM_LIBRARY})
-  endif()
-endif()
-
-include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
-set(LIBS ${LIBS} ${Boost_LIBRARIES})
-
-# ----------------------------------------------------------------------
-# ZLIB
-
-# ----------------------------------------------------------------------
-# Thrift
-
-# find thrift headers and libs
-find_package(Thrift)
-
-if (NOT THRIFT_FOUND)
-  set(ZLIB_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/zlib_ep/src/zlib_ep-install")
-  set(ZLIB_HOME "${ZLIB_PREFIX}")
-  set(ZLIB_INCLUDE_DIR "${ZLIB_PREFIX}/include")
-  if (MSVC)
-    if (${UPPERCASE_BUILD_TYPE} STREQUAL "DEBUG")
-      set(ZLIB_STATIC_LIB_NAME zlibstaticd.lib)
-    else()
-      set(ZLIB_STATIC_LIB_NAME zlibstatic.lib)
-    endif()
-  else()
-    set(ZLIB_STATIC_LIB_NAME libz.a)
-  endif()
-  set(ZLIB_STATIC_LIB "${ZLIB_PREFIX}/lib/${ZLIB_STATIC_LIB_NAME}")
-  set(ZLIB_CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-    -DCMAKE_INSTALL_PREFIX=${ZLIB_PREFIX}
-    -DCMAKE_C_FLAGS=${EP_C_FLAGS}
-    -DBUILD_SHARED_LIBS=OFF)
-  ExternalProject_Add(zlib_ep
-    URL "http://zlib.net/fossils/zlib-1.2.8.tar.gz"
-    BUILD_BYPRODUCTS "${ZLIB_STATIC_LIB}"
-    ${ZLIB_BUILD_BYPRODUCTS}
-    ${EP_LOG_OPTIONS}
-    CMAKE_ARGS ${ZLIB_CMAKE_ARGS})
-
-  set(THRIFT_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/thrift_ep/src/thrift_ep-install")
-  set(THRIFT_HOME "${THRIFT_PREFIX}")
-  set(THRIFT_INCLUDE_DIR "${THRIFT_PREFIX}/include")
-  set(THRIFT_COMPILER "${THRIFT_PREFIX}/bin/thrift")
-  set(THRIFT_CMAKE_ARGS "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
-                        "-DCMAKE_CXX_FLAGS=${EP_CXX_FLAGS}"
-                        "-DCMAKE_C_FLAGS=${EP_C_FLAGS}"
-                        "-DCMAKE_INSTALL_PREFIX=${THRIFT_PREFIX}"
-                        "-DCMAKE_INSTALL_RPATH=${THRIFT_PREFIX}/lib"
-                        "-DBUILD_SHARED_LIBS=OFF"
-                        "-DBUILD_TESTING=OFF"
-                        "-DBUILD_EXAMPLES=OFF"
-                        "-DBUILD_TUTORIALS=OFF"
-                        "-DWITH_QT4=OFF"
-                        "-DWITH_C_GLIB=OFF"
-                        "-DWITH_JAVA=OFF"
-                        "-DWITH_PYTHON=OFF"
-                        "-DWITH_HASKELL=OFF"
-                        "-DWITH_CPP=ON"
-                        "-DWITH_STATIC_LIB=ON"
-                        "-DWITH_LIBEVENT=OFF"
-                        )
-
-  # Thrift also uses boost. Forward important boost settings if there were ones passed.
-  if (DEFINED BOOST_ROOT)
-    set(THRIFT_CMAKE_ARGS ${THRIFT_CMAKE_ARGS} "-DBOOST_ROOT=${BOOST_ROOT}")
-  endif()
-  if (DEFINED Boost_NAMESPACE)
-    set(THRIFT_CMAKE_ARGS ${THRIFT_CMAKE_ARGS} "-DBoost_NAMESPACE=${Boost_NAMESPACE}")
-  endif()
-
-  set(THRIFT_STATIC_LIB_NAME "${CMAKE_STATIC_LIBRARY_PREFIX}thrift")
-  if (MSVC)
-    if (PARQUET_USE_STATIC_CRT)
-      set(THRIFT_STATIC_LIB_NAME "${THRIFT_STATIC_LIB_NAME}mt")
-      set(THRIFT_CMAKE_ARGS ${THRIFT_CMAKE_ARGS} "-DWITH_MT=ON")
-    else()
-      set(THRIFT_STATIC_LIB_NAME "${THRIFT_STATIC_LIB_NAME}md")
-      set(THRIFT_CMAKE_ARGS ${THRIFT_CMAKE_ARGS} "-DWITH_MT=OFF")
-    endif()
-  endif()
-  if (${UPPERCASE_BUILD_TYPE} STREQUAL "DEBUG")
-    set(THRIFT_STATIC_LIB_NAME "${THRIFT_STATIC_LIB_NAME}d")
-  endif()
-  set(THRIFT_STATIC_LIB "${THRIFT_PREFIX}/lib/${THRIFT_STATIC_LIB_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX}")
-
-  if (MSVC)
-    set(WINFLEXBISON_VERSION 2.4.9)
-    set(WINFLEXBISON_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/winflexbison_ep/src/winflexbison_ep-install")
-    ExternalProject_Add(winflexbison_ep
-      URL https://github.com/lexxmark/winflexbison/releases/download/v.${WINFLEXBISON_VERSION}/win_flex_bison-${WINFLEXBISON_VERSION}.zip
-      URL_HASH MD5=a2e979ea9928fbf8567e995e9c0df765
-      SOURCE_DIR ${WINFLEXBISON_PREFIX}
-      CONFIGURE_COMMAND ""
-      BUILD_COMMAND ""
-      INSTALL_COMMAND ""
-      ${EP_LOG_OPTIONS})
-    set(THRIFT_DEPENDENCIES ${THRIFT_DEPENDENCIES} winflexbison_ep)
-
-    set(THRIFT_CMAKE_ARGS "-DFLEX_EXECUTABLE=${WINFLEXBISON_PREFIX}/win_flex.exe"
-                          "-DBISON_EXECUTABLE=${WINFLEXBISON_PREFIX}/win_bison.exe"
-                          "-DZLIB_INCLUDE_DIR=${ZLIB_INCLUDE_DIR}"
-                          "-DZLIB_LIBRARY=${ZLIB_STATIC_LIB}"
-                          "-DWITH_SHARED_LIB=OFF"
-                          "-DWITH_PLUGIN=OFF"
-                          ${THRIFT_CMAKE_ARGS})
-    set(THRIFT_DEPENDENCIES ${THRIFT_DEPENDENCIES} zlib_ep)
-  elseif (APPLE)
-    if (DEFINED BISON_EXECUTABLE)
-      set(THRIFT_CMAKE_ARGS "-DBISON_EXECUTABLE=${BISON_EXECUTABLE}"
-                            ${THRIFT_CMAKE_ARGS})
-    endif()
-  endif()
-
-  ExternalProject_Add(thrift_ep
-    URL "http://archive.apache.org/dist/thrift/${THRIFT_VENDOR_VERSION}/thrift-${THRIFT_VENDOR_VERSION}.tar.gz"
-    BUILD_BYPRODUCTS "${THRIFT_STATIC_LIB}" "${THRIFT_COMPILER}"
-    CMAKE_ARGS ${THRIFT_CMAKE_ARGS}
-    DEPENDS ${THRIFT_DEPENDENCIES}
-    ${EP_LOG_OPTIONS})
-
-  set(THRIFT_VENDORED 1)
-else()
-  set(THRIFT_VENDORED 0)
-endif()
-
-include_directories(SYSTEM ${THRIFT_INCLUDE_DIR} ${THRIFT_INCLUDE_DIR}/thrift)
-message(STATUS "Thrift include dir: ${THRIFT_INCLUDE_DIR}")
-message(STATUS "Thrift static library: ${THRIFT_STATIC_LIB}")
-message(STATUS "Thrift compiler: ${THRIFT_COMPILER}")
-message(STATUS "Thrift version: ${THRIFT_VERSION}")
-add_library(thriftstatic STATIC IMPORTED)
-set_target_properties(thriftstatic PROPERTIES IMPORTED_LOCATION ${THRIFT_STATIC_LIB})
-
-if (THRIFT_VENDORED)
-  add_dependencies(thriftstatic thrift_ep)
-endif()
-
-if (PARQUET_THRIFT_USE_BOOST)
-  add_definitions(-DPARQUET_THRIFT_USE_BOOST)
-  message(STATUS "Using Boost in Thrift header")
-endif()
-
-## GTest
-if(PARQUET_BUILD_TESTS AND NOT IGNORE_OPTIONAL_PACKAGES)
-  add_custom_target(unittest ctest -L unittest)
-
-  if("$ENV{GTEST_HOME}" STREQUAL "")
-    if(APPLE)
-      set(GTEST_CMAKE_CXX_FLAGS "${EP_CXX_FLAGS} -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-value -Wno-ignored-attributes")
-    elseif(MSVC)
-      # Workaround https://github.com/google/googletest/issues/1111 until
-      # a new gtest version is released
-      set(GTEST_CMAKE_CXX_FLAGS "${EP_CXX_FLAGS} -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING")
-    else()
-      set(GTEST_CMAKE_CXX_FLAGS "${EP_CXX_FLAGS}")
-    endif()
-
-    set(GTEST_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/googletest_ep-prefix/src/googletest_ep")
-    set(GTEST_INCLUDE_DIR "${GTEST_PREFIX}/include")
-    set(GTEST_STATIC_LIB
-      "${GTEST_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}")
-    set(GTEST_MAIN_STATIC_LIB
-      "${GTEST_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}gtest_main${CMAKE_STATIC_LIBRARY_SUFFIX}")
-
-    set(GTEST_CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-                         -DCMAKE_INSTALL_PREFIX=${GTEST_PREFIX}
-                         -DCMAKE_CXX_FLAGS=${GTEST_CMAKE_CXX_FLAGS})
-
-    if (MSVC AND NOT PARQUET_USE_STATIC_CRT)
-      set(GTEST_CMAKE_ARGS ${GTEST_CMAKE_ARGS} -Dgtest_force_shared_crt=ON)
-    endif()
-
-    ExternalProject_Add(googletest_ep
-      URL "https://github.com/google/googletest/archive/release-${GTEST_VERSION}.tar.gz"
-      BUILD_BYPRODUCTS "${GTEST_STATIC_LIB}" "${GTEST_MAIN_STATIC_LIB}"
-      CMAKE_ARGS ${GTEST_CMAKE_ARGS}
-      ${EP_LOG_OPTIONS})
-    set(GTEST_VENDORED 1)
-  else()
-    find_package(GTest REQUIRED)
-    set(GTEST_VENDORED 0)
-  endif()
-
-  message(STATUS "GTest include dir: ${GTEST_INCLUDE_DIR}")
-  message(STATUS "GTest static library: ${GTEST_STATIC_LIB}")
-  include_directories(SYSTEM ${GTEST_INCLUDE_DIR})
-
-  add_library(gtest STATIC IMPORTED)
-  set_target_properties(gtest PROPERTIES IMPORTED_LOCATION ${GTEST_STATIC_LIB})
-
-  add_library(gtest_main STATIC IMPORTED)
-  set_target_properties(gtest_main PROPERTIES IMPORTED_LOCATION
-    ${GTEST_MAIN_STATIC_LIB})
-
-  if(GTEST_VENDORED)
-    add_dependencies(gtest googletest_ep)
-    add_dependencies(gtest_main googletest_ep)
-  endif()
-endif()
-
-## Google Benchmark
-if ("$ENV{GBENCHMARK_HOME}" STREQUAL "")
-  set(GBENCHMARK_HOME ${THIRDPARTY_DIR}/installed)
-endif()
-
-if(PARQUET_BUILD_BENCHMARKS AND NOT IGNORE_OPTIONAL_PACKAGES)
-  add_custom_target(runbenchmark ctest -L benchmark)
-
-  if("$ENV{GBENCHMARK_HOME}" STREQUAL "")
-    set(GBENCHMARK_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/gbenchmark_ep/src/gbenchmark_ep-install")
-    set(GBENCHMARK_INCLUDE_DIR "${GBENCHMARK_PREFIX}/include")
-    set(GBENCHMARK_STATIC_LIB "${GBENCHMARK_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}benchmark${CMAKE_STATIC_LIBRARY_SUFFIX}")
-    set(GBENCHMARK_CMAKE_ARGS
-          "-DCMAKE_INSTALL_PREFIX:PATH=${GBENCHMARK_PREFIX}"
-          "-DBENCHMARK_ENABLE_TESTING=OFF"
-          "-DCMAKE_CXX_FLAGS=${EP_CXX_FLAGS}")
-    if (MSVC)
-      set(GBENCHMARK_CMAKE_ARGS ${GBENCHMARK_CMAKE_ARGS} "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
-    else()
-      set(GBENCHMARK_CMAKE_ARGS ${GBENCHMARK_CMAKE_ARGS} "-DCMAKE_BUILD_TYPE=Release")
-    endif()
-    if (APPLE)
-      set(GBENCHMARK_CMAKE_ARGS ${GBENCHMARK_CMAKE_ARGS} "-DBENCHMARK_USE_LIBCXX=ON")
-    endif()
-
-    ExternalProject_Add(gbenchmark_ep
-      URL "https://github.com/google/benchmark/archive/v${GBENCHMARK_VERSION}.tar.gz"
-      BUILD_BYPRODUCTS "${GBENCHMARK_STATIC_LIB}"
-      CMAKE_ARGS ${GBENCHMARK_CMAKE_ARGS}
-      ${EP_LOG_OPTIONS})
-    set(GBENCHMARK_VENDORED 1)
-  else()
-    find_package(GBenchmark REQUIRED)
-    set(GBENCHMARK_VENDORED 0)
-  endif()
-
-  message(STATUS "GBenchmark include dir: ${GBENCHMARK_INCLUDE_DIR}")
-  message(STATUS "GBenchmark static library: ${GBENCHMARK_STATIC_LIB}")
-  include_directories(SYSTEM ${GBENCHMARK_INCLUDE_DIR})
-  add_library(gbenchmark STATIC IMPORTED)
-  set_target_properties(gbenchmark PROPERTIES IMPORTED_LOCATION ${GBENCHMARK_STATIC_LIB})
-
-  if(GBENCHMARK_VENDORED)
-    add_dependencies(gbenchmark gbenchmark_ep)
-  endif()
-endif()
-
-# ----------------------------------------------------------------------
-# Apache Arrow
-
-find_package(Arrow)
-if (NOT ARROW_FOUND)
-  include(ArrowExternalProject)
-  set(ARROW_VENDORED 1)
-else()
-  set(ARROW_VENDORED 0)
-endif()
-
-include_directories(SYSTEM ${ARROW_INCLUDE_DIR})
-add_library(arrow SHARED IMPORTED)
-if(MSVC)
-  set_target_properties(arrow
-                        PROPERTIES IMPORTED_IMPLIB "${ARROW_SHARED_IMPLIB}")
-else()
-  set_target_properties(arrow
-                        PROPERTIES IMPORTED_LOCATION "${ARROW_SHARED_LIB}")
-endif()
-add_library(arrow_static STATIC IMPORTED)
-set_target_properties(arrow_static PROPERTIES IMPORTED_LOCATION ${ARROW_STATIC_LIB})
-
-if (ARROW_VENDORED)
-  add_dependencies(arrow arrow_ep)
-  add_dependencies(arrow_static arrow_ep)
-endif()
diff --git a/cmake_modules/clean-all.cmake b/cmake_modules/clean-all.cmake
deleted file mode 100644
index 38e61da..0000000
--- a/cmake_modules/clean-all.cmake
+++ /dev/null
@@ -1,31 +0,0 @@
-# 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.
-
-set(cmake_generated ${CMAKE_BINARY_DIR}/CMakeCache.txt
-                    ${CMAKE_BINARY_DIR}/CTestTestfile.cmake
-                    ${CMAKE_BINARY_DIR}/cmake_install.cmake
-                    ${CMAKE_BINARY_DIR}/Makefile
-                    ${CMAKE_BINARY_DIR}/CMakeFiles
-)
-
-foreach(file ${cmake_generated})
-
-  if (EXISTS ${file})
-     file(REMOVE_RECURSE ${file})
-  endif()
-
-endforeach(file)
diff --git a/cmake_modules/parquet-cppConfig.cmake.in b/cmake_modules/parquet-cppConfig.cmake.in
deleted file mode 100644
index 47021d0..0000000
--- a/cmake_modules/parquet-cppConfig.cmake.in
+++ /dev/null
@@ -1,32 +0,0 @@
-# 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.
-
-set(PARQUET-CPP_VERSION x.y.z)
-
-@PACKAGE_INIT@
-
-set_and_check(PARQUET-CPP_INCLUDE_DIR "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
-set_and_check(PARQUET-CPP_LIB_DIR "@PACKAGE_CMAKE_INSTALL_LIBDIR@")
-
-set(_TMP_SUFFIX ${CMAKE_FIND_LIBRARY_SUFFIXES})
-FIND_LIBRARY(PARQUET_LIBRARY NAMES parquet PATHS ${PARQUET-CPP_LIB_DIR})
-set(PARQUET-CPP_LIBRARIES ${PARQUET_LIBRARY})
-
-set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
-FIND_LIBRARY(PARQUET_STATIC_LIBRARY NAMES parquet PATHS ${PARQUET-CPP_LIB_DIR})
-set(PARQUET-CPP_STATIC_LIBRARIES ${PARQUET_STATIC_LIBRARY})
-set(CMAKE_FIND_LIBRARY_SUFFIXES ${_TMP_SUFFIX})
diff --git a/data/alltypes_dictionary.parquet b/data/alltypes_dictionary.parquet
deleted file mode 100755
index e6da6ab..0000000
--- a/data/alltypes_dictionary.parquet
+++ /dev/null
Binary files differ
diff --git a/data/alltypes_plain.parquet b/data/alltypes_plain.parquet
deleted file mode 100755
index a63f5dc..0000000
--- a/data/alltypes_plain.parquet
+++ /dev/null
Binary files differ
diff --git a/data/alltypes_plain.snappy.parquet b/data/alltypes_plain.snappy.parquet
deleted file mode 100755
index 9809d67..0000000
--- a/data/alltypes_plain.snappy.parquet
+++ /dev/null
Binary files differ
diff --git a/data/bloom_filter.bin b/data/bloom_filter.bin
deleted file mode 100644
index c0e30ce..0000000
--- a/data/bloom_filter.bin
+++ /dev/null
Binary files differ
diff --git a/data/fixed_length_decimal.parquet b/data/fixed_length_decimal.parquet
deleted file mode 100644
index 69fce53..0000000
--- a/data/fixed_length_decimal.parquet
+++ /dev/null
Binary files differ
diff --git a/data/fixed_length_decimal_legacy.parquet b/data/fixed_length_decimal_legacy.parquet
deleted file mode 100644
index b0df62a..0000000
--- a/data/fixed_length_decimal_legacy.parquet
+++ /dev/null
Binary files differ
diff --git a/data/int32_decimal.parquet b/data/int32_decimal.parquet
deleted file mode 100644
index 5bf2d4e..0000000
--- a/data/int32_decimal.parquet
+++ /dev/null
Binary files differ
diff --git a/data/int64_decimal.parquet b/data/int64_decimal.parquet
deleted file mode 100644
index 5043bca..0000000
--- a/data/int64_decimal.parquet
+++ /dev/null
Binary files differ
diff --git a/data/nation.dict-malformed.parquet b/data/nation.dict-malformed.parquet
deleted file mode 100644
index 5008ac0..0000000
--- a/data/nation.dict-malformed.parquet
+++ /dev/null
Binary files differ
diff --git a/dev/README.md b/dev/README.md
deleted file mode 100644
index d567672..0000000
--- a/dev/README.md
+++ /dev/null
@@ -1,88 +0,0 @@
-<!---
-  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. See accompanying LICENSE file.
--->
-
-# Parquet Developer Scripts
-This directory contains scripts useful to developers when packaging,
-testing, or committing to Parquet.
-
-Merging a pull request requires being a committer on the project.
-
-* How to merge a Pull request:
-have an apache and apache-github remote setup
-```
-git remote add apache-github https://github.com/apache/parquet-cpp.git
-git remote add apache git@github.com:apache/parquet-cpp.git
-```
-run the following command
-```
-dev/merge_parquet_pr.py
-```
-
-Note:
-* The parent directory of your parquet repository must be called parquet-cpp
-* Without jira-python installed you'll have to close the JIRA manually
-
-example output:
-```
-Which pull request would you like to merge? (e.g. 34):
-```
-Type the pull request number (from https://github.com/apache/parquet-cpp/pulls) and hit enter.
-```
-=== Pull Request #X ===
-title	Blah Blah Blah
-source	repo/branch
-target	master
-url	https://api.github.com/repos/apache/parquet-cpp/pulls/X
-
-Proceed with merging pull request #3? (y/n): 
-```
-If this looks good, type y and hit enter.
-```
-From git-wip-us.apache.org:/repos/asf/parquet-cpp.git
- * [new branch]      master     -> PR_TOOL_MERGE_PR_3_MASTER
-Switched to branch 'PR_TOOL_MERGE_PR_3_MASTER'
-
-Merge complete (local ref PR_TOOL_MERGE_PR_3_MASTER). Push to apache? (y/n):
-```
-A local branch with the merge has been created.
-type y and hit enter to push it to apache master
-```
-Counting objects: 67, done.
-Delta compression using up to 4 threads.
-Compressing objects: 100% (26/26), done.
-Writing objects: 100% (36/36), 5.32 KiB, done.
-Total 36 (delta 17), reused 0 (delta 0)
-To git-wip-us.apache.org:/repos/asf/parquet-cpp.git
-   b767ac4..485658a  PR_TOOL_MERGE_PR_X_MASTER -> master
-Restoring head pointer to b767ac4e
-Note: checking out 'b767ac4e'.
-
-You are in 'detached HEAD' state. You can look around, make experimental
-changes and commit them, and you can discard any commits you make in this
-state without impacting any branches by performing another checkout.
-
-If you want to create a new branch to retain commits you create, you may
-do so (now or later) by using -b with the checkout command again. Example:
-
-  git checkout -b new_branch_name
-
-HEAD is now at b767ac4... Update README.md
-Deleting local branch PR_TOOL_MERGE_PR_X
-Deleting local branch PR_TOOL_MERGE_PR_X_MASTER
-Pull request #X merged!
-Merge hash: 485658a5
-
-Would you like to pick 485658a5 into another branch? (y/n):
-```
-For now just say n as we have 1 branch
diff --git a/dev/committers-guide.md b/dev/committers-guide.md
deleted file mode 100644
index f3fddfd..0000000
--- a/dev/committers-guide.md
+++ /dev/null
@@ -1,118 +0,0 @@
-<!---
-  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. See accompanying LICENSE file.
-
-  Original imported from Apache Aurora.
--->
-
-Committer's Guide
-=================
-
-Information for official Apache Parquet committers.
-
-Setting up your email account
------------------------------
-Once your Apache ID has been set up you can configure your account and add ssh keys and setup an
-email forwarding address at
-
-    http://id.apache.org
-
-Additional instructions for setting up your new committer email can be found at
-
-    http://www.apache.org/dev/user-email.html
-
-The recommended setup is to configure all services (mailing lists, JIRA) to send
-emails to your @apache.org email address.
-
-
-Creating a gpg key for releases
--------------------------------
-In order to create a release candidate you will need a gpg key published to an external key server
-and that key will need to be added to our KEYS file as well.
-
-1. Create a key:
-
-               gpg --gen-key
-
-2. Add your gpg key to the Apache Parquet {format,mr,cpp} KEYS file:
-
-               git clone git@github.com:apache/parquet-cpp.git
-               (gpg --list-sigs <KEY ID> && gpg --armor --export <KEY ID>) >> KEYS
-               git add KEYS && git commit -m "Adding gpg key for <APACHE ID>"
-               ./rbt post -o -g
-
-3. Publish the key to an external key server:
-
-               gpg --keyserver pgp.mit.edu --send-keys <KEY ID>
-
-4. Update the changes to the KEYS file to the Apache Parquet svn dist locations listed below:
-
-               https://dist.apache.org/repos/dist/dev/parquet/KEYS
-               https://dist.apache.org/repos/dist/release/parquet/KEYS
-
-5. Add your key to git config for use with the release scripts:
-
-               git config --global user.signingkey <KEY ID>
-
-
-Creating a release
-------------------
-The following will guide you through the steps to create a release candidate, vote, and finally an
-official Apache Parquet C++ release. Before starting your gpg key should be in the KEYS file and you
-must have access to commit to the dist.a.o repositories.
-
-1. Ensure that all issues resolved for this release candidate are tagged with the correct Fix
-Version in JIRA, the changelog script will use this to generate the CHANGELOG in step #2.
-To assign the fix version:
-
-    * Look up the [previous release date](https://issues.apache.org/jira/browse/parquet/?selectedTab=com.atlassian.jira.jira-projects-plugin:versions-panel).
-    * Query all issues resolved after that release date: `project = PARQUET AND status in (resolved, Closed) and fixVersion is empty and resolutiondate >= "YYYY/MM/DD"`
-    * In the upper right corner of the query result, select Tools > Bulk Edit.
-    * Select all issues > edit issue > set 'Change Fix Version/s' to the release version.
-    * Make sure to uncheck 'Send mail for this update' at the bottom.
-
-2. Prepare RELEASE-NOTES.md for the release. This just boils down to removing the "(Not yet
-released)" suffix from the impending release.
-
-2. Create a release candidate. This will automatically update the CHANGELOG and commit it, create a
-branch and update the current version within the trunk. To create a minor version update and publish
-it run
-
-               ./dev/release/release-candidate -l m -p
-
-3. Update, if necessary, the draft email created from the `release-candidate` script in step #2 and
-send the [VOTE] email to the dev@ mailing list. You can verify the release signature and checksums
-by running
-
-               ./dev/release/verify-release-candidate
-
-4. Wait for the vote to complete. If the vote fails close the vote by replying to the initial [VOTE]
-email sent in step #3 by editing the subject to [RESULT][VOTE] ... and noting the failure reason
-(example [here](http://markmail.org/message/d4d6xtvj7vgwi76f)). You'll also need to manually revert
-the commits generated by the release candidate script that incremented the snapshot version and
-updated the changelog. Once that is done, now address any issues and go back to step #1 and run
-again, this time you will use the -r flag to increment the release candidate version. This will
-automatically clean up the release candidate rc0 branch and source distribution.
-
-               ./dev/release/release-candidate -l m -r 1 -p
-
-5. Once the vote has successfully passed create the release
-
-**IMPORTANT: make sure to use the correct release at this final step (e.g.: `-r 1` if rc1 candidate
-has been voted for). Once the release tag is pushed it will be very hard to undo due to remote
-git pre-receive hook explicitly forbidding release tag manipulations.**
-
-               ./dev/release/release
-
-6. Update the draft email created fom the `release` script in step #5 to include the Apache ID's for
-all binding votes and send the [RESULT][VOTE] email to the dev@ mailing list.
-
diff --git a/dev/merge_parquet_pr.py b/dev/merge_parquet_pr.py
deleted file mode 100755
index dcb7af6..0000000
--- a/dev/merge_parquet_pr.py
+++ /dev/null
@@ -1,354 +0,0 @@
-#!/usr/bin/env python
-
-#
-# 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.
-#
-
-# Utility for creating well-formed pull request merges and pushing them to Apache.
-#   usage: ./apache-pr-merge.py    (see config env vars below)
-#
-# This utility assumes you already have local a Parquet git folder and that you
-# have added remotes corresponding to both (i) the github apache Parquet
-# mirror and (ii) the apache git repo.
-
-import json
-import os
-import re
-import subprocess
-import sys
-import tempfile
-import urllib2
-import getpass
-
-try:
-    import jira.client
-    JIRA_IMPORTED = True
-except ImportError:
-    JIRA_IMPORTED = False
-
-# Location of your Parquet git development area
-PARQUET_HOME = os.path.abspath(__file__).rsplit("/", 2)[0]
-PROJECT_NAME = PARQUET_HOME.rsplit("/", 1)[1]
-print "PARQUET_HOME = " + PARQUET_HOME
-print "PROJECT_NAME = " + PROJECT_NAME
-
-# Remote name which points to the Gihub site
-PR_REMOTE_NAME = os.environ.get("PR_REMOTE_NAME", "apache-github")
-# Remote name which points to Apache git
-PUSH_REMOTE_NAME = os.environ.get("PUSH_REMOTE_NAME", "apache")
-# ASF JIRA username
-JIRA_USERNAME = os.environ.get("JIRA_USERNAME")
-# ASF JIRA password
-JIRA_PASSWORD = os.environ.get("JIRA_PASSWORD")
-
-GITHUB_BASE = "https://github.com/apache/" + PROJECT_NAME + "/pull"
-GITHUB_API_BASE = "https://api.github.com/repos/apache/" + PROJECT_NAME
-JIRA_BASE = "https://issues.apache.org/jira/browse"
-JIRA_API_BASE = "https://issues.apache.org/jira"
-# Prefix added to temporary branches
-BRANCH_PREFIX = "PR_TOOL"
-
-os.chdir(PARQUET_HOME)
-
-
-def get_json(url):
-    try:
-        return json.load(urllib2.urlopen(url))
-    except urllib2.HTTPError as e:
-        print "Unable to fetch URL, exiting: %s" % url
-        sys.exit(-1)
-
-
-def fail(msg):
-    print msg
-    clean_up()
-    sys.exit(-1)
-
-
-def run_cmd(cmd):
-    if isinstance(cmd, list):
-        return subprocess.check_output(cmd)
-    else:
-        return subprocess.check_output(cmd.split(" "))
-
-
-def continue_maybe(prompt):
-    result = raw_input("\n%s (y/n): " % prompt)
-    if result.lower() != "y":
-        fail("Okay, exiting")
-
-
-original_head = run_cmd("git rev-parse HEAD")[:8]
-
-
-def clean_up():
-    print "Restoring head pointer to %s" % original_head
-    run_cmd("git checkout %s" % original_head)
-
-    branches = run_cmd("git branch").replace(" ", "").split("\n")
-
-    for branch in filter(lambda x: x.startswith(BRANCH_PREFIX), branches):
-        print "Deleting local branch %s" % branch
-        run_cmd("git branch -D %s" % branch)
-
-
-# merge the requested PR and return the merge hash
-def merge_pr(pr_num, target_ref):
-    pr_branch_name = "%s_MERGE_PR_%s" % (BRANCH_PREFIX, pr_num)
-    target_branch_name = "%s_MERGE_PR_%s_%s" % (BRANCH_PREFIX, pr_num, target_ref.upper())
-    run_cmd("git fetch %s pull/%s/head:%s" % (PR_REMOTE_NAME, pr_num, pr_branch_name))
-    run_cmd("git fetch %s %s:%s" % (PUSH_REMOTE_NAME, target_ref, target_branch_name))
-    run_cmd("git checkout %s" % target_branch_name)
-
-    had_conflicts = False
-    try:
-        run_cmd(['git', 'merge', pr_branch_name, '--squash'])
-    except Exception as e:
-        msg = "Error merging: %s\nWould you like to manually fix-up this merge?" % e
-        continue_maybe(msg)
-        msg = "Okay, please fix any conflicts and 'git add' conflicting files... Finished?"
-        continue_maybe(msg)
-        had_conflicts = True
-
-    commit_authors = run_cmd(['git', 'log', 'HEAD..%s' % pr_branch_name,
-                             '--pretty=format:%an <%ae>']).split("\n")
-    distinct_authors = sorted(set(commit_authors),
-                              key=lambda x: commit_authors.count(x), reverse=True)
-    primary_author = distinct_authors[0]
-    commits = run_cmd(['git', 'log', 'HEAD..%s' % pr_branch_name,
-                      '--pretty=format:%h [%an] %s']).split("\n\n")
-
-    merge_message_flags = []
-
-    merge_message_flags += ["-m", title]
-    if body != None:
-        merge_message_flags += ["-m", body]
-
-    authors = "\n".join(["Author: %s" % a for a in distinct_authors])
-
-    merge_message_flags += ["-m", authors]
-
-    if had_conflicts:
-        committer_name = run_cmd("git config --get user.name").strip()
-        committer_email = run_cmd("git config --get user.email").strip()
-        message = "This patch had conflicts when merged, resolved by\nCommitter: %s <%s>" % (
-            committer_name, committer_email)
-        merge_message_flags += ["-m", message]
-
-    # The string "Closes #%s" string is required for GitHub to correctly close the PR
-    merge_message_flags += [
-        "-m",
-        "Closes #%s from %s and squashes the following commits:" % (pr_num, pr_repo_desc)]
-    for c in commits:
-        merge_message_flags += ["-m", c]
-
-    run_cmd(['git', 'commit', '--author="%s"' % primary_author] + merge_message_flags)
-
-    continue_maybe("Merge complete (local ref %s). Push to %s?" % (
-        target_branch_name, PUSH_REMOTE_NAME))
-
-    try:
-        run_cmd('git push %s %s:%s' % (PUSH_REMOTE_NAME, target_branch_name, target_ref))
-    except Exception as e:
-        clean_up()
-        fail("Exception while pushing: %s" % e)
-
-    merge_hash = run_cmd("git rev-parse %s" % target_branch_name)[:8]
-    clean_up()
-    print("Pull request #%s merged!" % pr_num)
-    print("Merge hash: %s" % merge_hash)
-    return merge_hash
-
-
-def cherry_pick(pr_num, merge_hash, default_branch):
-    pick_ref = raw_input("Enter a branch name [%s]: " % default_branch)
-    if pick_ref == "":
-        pick_ref = default_branch
-
-    pick_branch_name = "%s_PICK_PR_%s_%s" % (BRANCH_PREFIX, pr_num, pick_ref.upper())
-
-    run_cmd("git fetch %s %s:%s" % (PUSH_REMOTE_NAME, pick_ref, pick_branch_name))
-    run_cmd("git checkout %s" % pick_branch_name)
-    run_cmd("git cherry-pick -sx %s" % merge_hash)
-
-    continue_maybe("Pick complete (local ref %s). Push to %s?" % (
-        pick_branch_name, PUSH_REMOTE_NAME))
-
-    try:
-        run_cmd('git push %s %s:%s' % (PUSH_REMOTE_NAME, pick_branch_name, pick_ref))
-    except Exception as e:
-        clean_up()
-        fail("Exception while pushing: %s" % e)
-
-    pick_hash = run_cmd("git rev-parse %s" % pick_branch_name)[:8]
-    clean_up()
-
-    print("Pull request #%s picked into %s!" % (pr_num, pick_ref))
-    print("Pick hash: %s" % pick_hash)
-    return pick_ref
-
-
-def fix_version_from_branch(branch, versions):
-    # Note: Assumes this is a sorted (newest->oldest) list of un-released versions
-    if branch == "master":
-        return versions[0]
-    else:
-        branch_ver = branch.replace("branch-", "")
-        return filter(lambda x: x.name.startswith(branch_ver), versions)[-1]
-
-def exctract_jira_id(title):
-    m = re.search('^(PARQUET-[0-9]+):.*$', title)
-    if m and m.groups > 0:
-        return m.group(1)
-    else:
-        fail("PR title should be prefixed by a jira id \"PARQUET-XXX: ...\", found: \"%s\"" % title)
-
-def check_jira(title):
-    jira_id = exctract_jira_id(title)
-    asf_jira = jira.client.JIRA({'server': JIRA_API_BASE},
-                                basic_auth=(JIRA_USERNAME, JIRA_PASSWORD))
-    try:
-        issue = asf_jira.issue(jira_id)
-    except Exception as e:
-        fail("ASF JIRA could not find %s\n%s" % (jira_id, e))
-
-def resolve_jira(title, merge_branches, comment):
-    asf_jira = jira.client.JIRA({'server': JIRA_API_BASE},
-                                basic_auth=(JIRA_USERNAME, JIRA_PASSWORD))
-
-    default_jira_id = exctract_jira_id(title)
-
-    jira_id = raw_input("Enter a JIRA id [%s]: " % default_jira_id)
-    if jira_id == "":
-        jira_id = default_jira_id
-
-    try:
-        issue = asf_jira.issue(jira_id)
-    except Exception as e:
-        fail("ASF JIRA could not find %s\n%s" % (jira_id, e))
-
-    cur_status = issue.fields.status.name
-    cur_summary = issue.fields.summary
-    cur_assignee = issue.fields.assignee
-    if cur_assignee is None:
-        cur_assignee = "NOT ASSIGNED!!!"
-    else:
-        cur_assignee = cur_assignee.displayName
-
-    if cur_status == "Resolved" or cur_status == "Closed":
-        fail("JIRA issue %s already has status '%s'" % (jira_id, cur_status))
-    print ("=== JIRA %s ===" % jira_id)
-    print ("summary\t\t%s\nassignee\t%s\nstatus\t\t%s\nurl\t\t%s/%s\n" % (
-        cur_summary, cur_assignee, cur_status, JIRA_BASE, jira_id))
-
-    versions = asf_jira.project_versions("PARQUET")
-    versions = sorted(versions, key=lambda x: x.name, reverse=True)
-    versions = filter(lambda x: x.raw['released'] is False, versions)
-
-    default_fix_versions = map(lambda x: fix_version_from_branch(x, versions).name, merge_branches)
-    for v in default_fix_versions:
-        # Handles the case where we have forked a release branch but not yet made the release.
-        # In this case, if the PR is committed to the master branch and the release branch, we
-        # only consider the release branch to be the fix version. E.g. it is not valid to have
-        # both 1.1.0 and 1.0.0 as fix versions.
-        (major, minor, patch) = v.split(".")
-        if patch == "0":
-            previous = "%s.%s.%s" % (major, int(minor) - 1, 0)
-            if previous in default_fix_versions:
-                default_fix_versions = filter(lambda x: x != v, default_fix_versions)
-    default_fix_versions = ",".join(default_fix_versions)
-
-    fix_versions = raw_input("Enter comma-separated fix version(s) [%s]: " % default_fix_versions)
-    if fix_versions == "":
-        fix_versions = default_fix_versions
-    fix_versions = fix_versions.replace(" ", "").split(",")
-
-    def get_version_json(version_str):
-        return filter(lambda v: v.name == version_str, versions)[0].raw
-
-    jira_fix_versions = map(lambda v: get_version_json(v), fix_versions)
-
-    resolve = filter(lambda a: a['name'] == "Resolve Issue", asf_jira.transitions(jira_id))[0]
-    asf_jira.transition_issue(
-        jira_id, resolve["id"], fixVersions=jira_fix_versions, comment=comment)
-
-    print "Succesfully resolved %s with fixVersions=%s!" % (jira_id, fix_versions)
-
-
-if not JIRA_USERNAME:
-    JIRA_USERNAME =  raw_input("Env JIRA_USERNAME not set, please enter your JIRA username:")
-
-if not JIRA_PASSWORD:
-    JIRA_PASSWORD =  getpass.getpass("Env JIRA_PASSWORD not set, please enter your JIRA password:")
-
-branches = get_json("%s/branches" % GITHUB_API_BASE)
-branch_names = filter(lambda x: x.startswith("branch-"), [x['name'] for x in branches])
-# Assumes branch names can be sorted lexicographically
-# Julien: I commented this out as we don't have any "branch-*" branch yet
-#latest_branch = sorted(branch_names, reverse=True)[0]
-
-pr_num = raw_input("Which pull request would you like to merge? (e.g. 34): ")
-pr = get_json("%s/pulls/%s" % (GITHUB_API_BASE, pr_num))
-
-url = pr["url"]
-title = pr["title"]
-check_jira(title)
-body = pr["body"]
-target_ref = pr["base"]["ref"]
-user_login = pr["user"]["login"]
-base_ref = pr["head"]["ref"]
-pr_repo_desc = "%s/%s" % (user_login, base_ref)
-
-if pr["merged"] is True:
-    print "Pull request %s has already been merged, assuming you want to backport" % pr_num
-    merge_commit_desc = run_cmd([
-        'git', 'log', '--merges', '--first-parent',
-        '--grep=pull request #%s' % pr_num, '--oneline']).split("\n")[0]
-    if merge_commit_desc == "":
-        fail("Couldn't find any merge commit for #%s, you may need to update HEAD." % pr_num)
-
-    merge_hash = merge_commit_desc[:7]
-    message = merge_commit_desc[8:]
-
-    print "Found: %s" % message
-    maybe_cherry_pick(pr_num, merge_hash, latest_branch)
-    sys.exit(0)
-
-if not bool(pr["mergeable"]):
-    msg = "Pull request %s is not mergeable in its current form.\n" % pr_num + \
-        "Continue? (experts only!)"
-    continue_maybe(msg)
-
-print ("\n=== Pull Request #%s ===" % pr_num)
-print ("title\t%s\nsource\t%s\ntarget\t%s\nurl\t%s" % (
-    title, pr_repo_desc, target_ref, url))
-continue_maybe("Proceed with merging pull request #%s?" % pr_num)
-
-merged_refs = [target_ref]
-
-merge_hash = merge_pr(pr_num, target_ref)
-
-pick_prompt = "Would you like to pick %s into another branch?" % merge_hash
-while raw_input("\n%s (y/n): " % pick_prompt).lower() == "y":
-    merged_refs = merged_refs + [cherry_pick(pr_num, merge_hash, latest_branch)]
-
-if JIRA_IMPORTED:
-    continue_maybe("Would you like to update the associated JIRA?")
-    jira_comment = "Issue resolved by pull request %s\n[%s/%s]" % (pr_num, GITHUB_BASE, pr_num)
-    resolve_jira(title, merged_refs, jira_comment)
-else:
-    print "Could not find jira-python library. Run 'sudo pip install jira-python' to install."
-    print "Exiting without trying to close the associated JIRA."
diff --git a/dev/release/README.md b/dev/release/README.md
deleted file mode 100644
index 142ab64..0000000
--- a/dev/release/README.md
+++ /dev/null
@@ -1,30 +0,0 @@
-<!---
-  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. See accompanying LICENSE file.
--->
-
-
-How to release
-==============
-
-1. Do a fresh `git clone` of the repository using the ASF git as origin.
-2. Set the git author to your gpg signing key using `git config --local user.email "<mail>"`.
-3. Create an RC using `./dev/release/release-candidate -r <rcNum> -v <version>` starting with `rcNum=0`.
-   You could first do a dry-run by adding `-p` at the end.
-4. Check that the uploaded RC is valid using `./dev/release/verify-release-candidate <version> <rcNum>`.
-5. Send the generated mail to dev@parquet.apache.org.
-6. Wait for the vote to end, either proceed to the next step or abort the RC and continue with the
-   necessary fixes.
-7. In the release SVN, copy the contents of the RC folder into the release folder.
-8. Delete the previous `parquet-cpp` release from SVN.
-9. Cherry-pick the commits in the `master-after-X` branch into master.
-10. Send out the release mail to `dev@parquet.apache.org` and `announce@apache.org`.
diff --git a/dev/release/changelog b/dev/release/changelog
deleted file mode 100755
index d6ed9f2..0000000
--- a/dev/release/changelog
+++ /dev/null
@@ -1,155 +0,0 @@
-#!/usr/bin/env ruby
-#
-# 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.
-#
-# Updates the CHANGELOG for the specified Apache Parquet C++ release, if no
-# version override is specified then .parquetcppversion will be read and used.
-# The version string will need to match the Apache Parquet C++ jira tickets
-# fixVersion to generate this list.
-#
-require 'rubygems'
-require 'json'
-require 'uri'
-require 'net/http'
-require 'net/https'
-require 'openssl'
-require 'tempfile'
-
-def http_post(uri, params={}, headers={}, body=nil, debug=false)
-  http = Net::HTTP.new(uri.host, uri.port)
-  http.set_debug_output($stdout) if debug
-  if uri.scheme == "https" || uri.port == 443
-    http.use_ssl = true
-    http.verify_mode = OpenSSL::SSL::VERIFY_NONE
-  end
-  response = nil
-
-  begin
-    request = Net::HTTP::Post.new(uri.request_uri)
-    request.set_form_data(params) if (params && params.size > 1)
-    request.basic_auth uri.user, uri.password if uri.user
-    request.body = body if body
-
-    headers.each_pair do |name, value|
-      request[name] = value
-    end
-
-    response = http.request(request)
-  rescue Exception => e
-    raise "Error posting to #{uri.to_s}. #{e}"
-  end
-
-  response
-end
-
-def get_jira_issues_for_query(url, jql, startAt=0, maxResults=100)
-  puts(jql)
-  begin
-    request_body = { :jql => jql, :startAt => startAt, :maxResults => maxResults}
-    response = http_post(
-      URI(url),
-      {},
-      {"content-type" => 'application/json', "accept" => "application/json"},
-      request_body.to_json
-    )
-  rescue StandardError => e
-    raise "Error executing jql query: #{jql}. #{e}"
-  end
-
-  begin
-    results = JSON.parse(response.body)
-  rescue StandardError => e
-    raise "Error parsing json result"
-  end
-
-  results
-end
-
-def get_all_jira_issues_for_query(url, jql)
-  startAt = 0
-  maxResults = 100
-
-  results = []
-  begin
-    res = get_jira_issues_for_query(url, jql, startAt, maxResults)
-    results.concat(res['issues']) if res && res.has_key?('issues')
-    startAt = startAt + maxResults
-  end until (results.size() == res['total'] )
-
-  results
-end
-
-base_dir = `git rev-parse --show-toplevel`.strip
-
-# Get the current version from the .parquetcppversion file if no version override is provided
-version = nil
-if ARGV[0].nil?
-  version = nil
-  Dir.chdir(base_dir) do
-    version = File.read('.parquetcppversion').strip
-  end
-else
-  version = ARGV[0]
-end
-
-raise "Unable to read .parquetcppversion" if version.nil?
-
-jira_base_url = "https://issues.apache.org/jira"
-jira_search_url = "/rest/api/2/search"
-jira_url = jira_base_url + jira_search_url
-
-jql="project=PARQUET " \
-    "AND fixVersion='cpp-#{version}' " \
-    "AND status = Resolved " \
-    "AND resolution in (Fixed, Done) " \
-    "ORDER BY issuetype DESC"
-
-# Fetch all the issues available for the given jql query
-results = get_all_jira_issues_for_query(jira_url, jql)
-
-changelog = {}
-# Loop through and add all results
-results.each do |issue|
-  key = issue['key']
-  summary = issue['fields']['summary']
-  type = issue['fields']['issuetype']['name']
-
-  changelog_entry = "[#{key}] - #{summary}"
-
-  if !changelog[type].nil?
-    changelog[type] << changelog_entry
-  else
-    changelog[type] = [changelog_entry]
-  end
-end
-
-# Merge the new updates and the existing changelog
-tmpfile = Tempfile.open('parquet-cpp.changelog')
-begin
-  tmpfile.puts "Parquet C++ #{version}", "-" * 80
-  changelog.keys.sort.each do |type|
-    tmpfile.puts "## #{type}"
-    changelog[type].each { |entry| tmpfile.puts "    * #{entry}" }
-    tmpfile.puts ""
-  end
-  # Append all the existing CHANGELOG entries and write the new CHANGELOG file
-  tmpfile.puts ""
-  changelog_file = File.join(base_dir, 'CHANGELOG')
-  tmpfile.write File.read(changelog_file) if File.exist?(changelog_file)
-  tmpfile.rewind
-  tmpfile.flush
-  File.open(changelog_file,"w+") {|f|  f.write(tmpfile.read) }
-ensure
-  tmpfile.close
-  tmpfile.unlink
-end
diff --git a/dev/release/release-candidate b/dev/release/release-candidate
deleted file mode 100755
index 88aa27a..0000000
--- a/dev/release/release-candidate
+++ /dev/null
@@ -1,316 +0,0 @@
-#!/bin/bash
-#
-# 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.
-#
-#
-# This script is used to create a release candidate. It will update the current
-# .parquetcppversion as well as creates a tag for the new release candidate and
-# publishes the source distribution and signatures to be voted on.
-#
-#   master~1 (0.5.0-snapshot) ----- master (0.6.0-snapshot)
-#                             \---- 0.5.0 (0.5.0)
-#
-# A email template will be generated after successfully generating a release
-# candidate which will need to be sent to the dev@ and private@ mailing lists.
-#
-set -o errexit
-set -o nounset
-
-rc_number=0
-override_version=''
-parquetcpp_git_web_url='https://gitbox.apache.org/repos/asf?p=parquet-cpp.git'
-parquet_svn_dist_url='https://dist.apache.org/repos/dist/dev/parquet'
-
-function print_help_and_exit {
-cat <<EOF
-Apache Parquet C++ release candidate tool.
-
-Usage: $0 [-h] [-l p|m|M] [-r #] [-p | publish]
-
-  -h  Print this help message and exit
-  -l  Increment level, must be one of:
-        p, patch (default)
-        m, minor
-        M, major
-  -v  Override the existing version in .parquetcppversion
-  -r  Release candidate number (default: 0)
-  -p  Publish the release candidate (default: dry-run, does not publish anything)
-EOF
-exit 0
-}
-
-publish=0
-increment_level="patch"
-rc_number=0
-while getopts ":hl:v:r:p" opt; do
-  case $opt in
-    l)
-      case ${OPTARG} in
-        'p' | 'patch') increment_level='patch' ;;
-        'm' | 'minor') increment_level='minor' ;;
-        'M' | 'major') increment_level='major' ;;
-         *) echo 'Unknown increment level'; exit 1 ;;
-      esac
-      ;;
-    r)
-      rc_number=${OPTARG}
-      ;;
-    p)
-      publish=1
-      ;;
-    h)
-      print_help_and_exit
-      ;;
-    v)
-      override_version=${OPTARG}
-      ;;
-    *  )
-      echo "Unknown option: -$OPTARG"
-      print_help_and_exit
-      ;;
-  esac
-done
-
-shift $(($OPTIND - 1))
-if [[ "${1:-dry-run}" == "publish" ]]; then
-  publish=1
-fi
-
-# Update local repository
-git fetch --all -q
-git fetch --tags -q
-
-# Verify that this is a clean repository
-if [[ -n "`git status --porcelain`" ]]; then
-  echo "ERROR: Please run from a clean git repository."
-  exit 1
-elif [[ "`git rev-parse --abbrev-ref HEAD`" != "master" ]]; then
-  echo "ERROR: This script must be run from master."
-  exit 1
-fi
-
-if [[ ! -f .parquetcppversion ]]; then
-  echo "Warrning: This script must be run from the root of the repository"
-  exit 1
-fi
-
-# Calculate the new version string
-current_version=$(cat .parquetcppversion | tr '[a-z]' '[A-Z]')
-if ! [[ $current_version =~ .*-SNAPSHOT ]]; then
-  echo "ERROR: .parquetcppversion is required to contain 'SNAPSHOT', it is ${current_version}"
-  exit 1
-else
-  if [[ $override_version != "" ]]; then
-    current_version=$override_version
-  fi
-
-  major=`echo $current_version | cut -d. -f1`
-  minor=`echo $current_version | cut -d. -f2`
-  patch=`echo $current_version | cut -d. -f3 | cut -d- -f1`
-
-  current_version="${major}.${minor}.${patch}"
-
-  if [[ $increment_level == "patch" ]]; then
-    new_master_version="${major}.${minor}.$((patch + 1))"
-  elif [[ $increment_level == "minor" ]]; then
-    new_master_version="${major}.$((minor + 1)).0"
-  elif [[ $increment_level == "major" ]]; then
-    new_master_version="$((major + 1)).0.0"
-  else
-    echo "Unknown release increment ${increment_level}"
-    exit 1
-  fi
-
-  new_snapshot_version="${new_master_version}-SNAPSHOT"
-fi
-
-# Add the rc tag to the current version
-rc_version="${current_version}-rc${rc_number}"
-version_tag="apache-parquet-cpp-${current_version}"
-rc_version_tag="apache-parquet-cpp-${rc_version}"
-
-echo
-echo "Generating release candidate ${rc_version_tag}"
-echo
-
-# Make sure the tag does not exist
-if git rev-parse ${version_tag} >/dev/null 2>&1; then
-  echo "ERROR: tag ${version_tag} exists."
-  exit 1
-fi
-
-if git rev-parse ${rc_version_tag} >/dev/null 2>&1; then
-  echo "ERROR: tag ${rc_version_tag} exists."
-  exit 1
-fi
-
-# Reset instructions
-current_git_rev=$(git rev-parse HEAD)
-function print_reset_instructions {
-cat <<EOF
-To roll back your local repo you will need to run:
-
-  git checkout master
-  git reset --hard ${current_git_rev}
-  git tag -d ${rc_version_tag}
-  git branch -D stage_${rc_version}
-EOF
-}
-
-# If anything goes wrong from here then print roll back instructions before exiting.
-function print_rollback_instructions {
-  echo "ERROR: Looks like something has failed while creating the release candidate."
-  print_reset_instructions
-}
-trap print_rollback_instructions EXIT
-
-# All check are now complete, before we start alert if we are in dry-run
-if [[ $publish == 0 ]]; then
-  echo "Performing dry-run, run with '-p' when you are ready to run and publish a release candidate"
-fi
-
-# This should be a clean repo we are working against. Run clean just to ensure it is.
-git clean -fdxq
-
-echo "Generating changelog"
-./dev/release/changelog $current_version
-git add CHANGELOG
-git commit -m "Updating CHANGELOG for ${current_version} release."
-
-echo "Committing updated .parquetcppversion on master"
-echo $new_snapshot_version > .parquetcppversion
-git add .parquetcppversion
-git commit -m "Incrementing snapshot version to ${new_snapshot_version}."
-
-echo "Creating ${rc_version} staging branch"
-git checkout -b "stage_${rc_version}"
-
-echo "Updating .parquetcppversion on staging branch"
-# Increment the version and create a branch
-echo ${current_version} > .parquetcppversion
-git add .parquetcppversion
-git commit -m "Updating .parquetcppversion to ${current_version}."
-
-# Build the source distribution from the new branch
-echo "Building the source distribution"
-dist_dir=dist
-dist_name="${version_tag}"
-
-mkdir -p ${dist_dir}
-git archive --prefix=${dist_name}/ -o ${dist_dir}/${dist_name}.tar.gz HEAD
-pushd ${dist_dir}
-  # Sign the tarball.
-  echo "Signing the distribution"
-  gpg --armor --output ${dist_name}.tar.gz.asc --detach-sig ${dist_name}.tar.gz
-
-  # Create the checksums
-  echo "Creating checksums"
-  gpg --print-md MD5 ${dist_name}.tar.gz > ${dist_name}.tar.gz.md5
-  sha1sum ${dist_name}.tar.gz > ${dist_name}.tar.gz.sha1
-  sha256sum ${dist_name}.tar.gz > ${dist_name}.tar.gz.sha256
-  sha512sum ${dist_name}.tar.gz > ${dist_name}.tar.gz.sha512
-popd
-
-parquet_svn_rc_url="${parquet_svn_dist_url}/apache-parquet-cpp-${rc_version}"
-
-# Publish release candidate to svn and commit and push the new git tag
-if [[ $publish == 1 ]]; then
-  echo "Publishing release candidate to ${parquet_svn_rc_url}"
-  svn mkdir ${parquet_svn_rc_url} -m "parquet-cpp-${current_version} release candidate ${rc_version}"
-  svn co --depth=empty ${parquet_svn_rc_url} ${dist_dir}
-  pushd ${dist_dir}
-  svn add ${dist_name}*
-  svn ci -m "parquet-cpp-${current_version} release candidate ${rc_version}"
-  popd
-
-  echo "Creating tag ${rc_version_tag}"
-  git tag -s ${rc_version_tag} \
-    -m "Apache Parquet C++ ${current_version} release candidate ${rc_version}"
-  git push origin "${rc_version_tag}"
-
-  echo "Pushing updated .parquetcppversion to master"
-  git checkout master
-  git push origin "master:master-after-${rc_version_tag}"
-fi
-
-echo "Done creating the release candidate. The following draft email has been created"
-echo "to send to the dev@parquet.apache.org mailing list"
-echo
-
-# Create the email template for the release candidate to be sent to the mailing lists.
-if [[ $(uname) == Darwin ]]; then
-  vote_end=$(date -v+3d)
-else
-  vote_end=$(date -d+3days)
-fi
-
-MESSAGE=$(cat <<__EOF__
-To: dev@parquet.apache.org
-Subject: [VOTE] Release Apache Parquet C++ ${current_version} RC${rc_number}
-
-All,
-
-I propose that we accept the following release candidate as the official
-Apache Parquet C++ ${current_version} release.
-
-Parquet C++ ${rc_version} includes the following:
----
-The CHANGELOG for the release is available at:
-${parquetcpp_git_web_url}&f=CHANGELOG&hb=${rc_version_tag}
-
-The tag used to create the release candidate is:
-${parquetcpp_git_web_url};a=shortlog;h=refs/tags/${rc_version_tag}
-
-The release candidate is available at:
-${parquet_svn_rc_url}/${dist_name}.tar.gz
-
-The MD5 checksum of the release candidate can be found at:
-${parquet_svn_rc_url}/${dist_name}.tar.gz.md5
-
-The signature of the release candidate can be found at:
-${parquet_svn_rc_url}/${dist_name}.tar.gz.asc
-
-The GPG key used to sign the release are available at:
-${parquet_svn_dist_url}/KEYS
-
-The release is based on the commit hash ${current_git_rev}.
-
-Please download, verify, and test.
-
-The vote will close on ${vote_end}
-
-[ ] +1 Release this as Apache Parquet C++ ${current_version}
-[ ] +0
-[ ] -1 Do not release this as Apache Parquet C++ ${current_version} because...
-
-__EOF__
-)
-
-echo "--------------------------------------------------------------------------------"
-echo
-echo "${MESSAGE}"
-echo
-echo "--------------------------------------------------------------------------------"
-echo
-
-# Print reset instructions if this was a dry-run
-if [[ $publish == 0 ]]; then
-  echo
-  echo "This was a dry run, nothing has been published."
-  echo
-  print_reset_instructions
-fi
-
-# Unset error message handler and exit
-trap '' EXIT
-exit 0
diff --git a/dev/release/run-rat.sh b/dev/release/run-rat.sh
deleted file mode 100755
index 2f0d4ff..0000000
--- a/dev/release/run-rat.sh
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/bin/bash
-#
-# 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.
-#
-
-# download apache rat
-curl -s https://repo1.maven.org/maven2/org/apache/rat/apache-rat/0.12/apache-rat-0.12.jar > apache-rat-0.12.jar
-
-RAT="java -jar apache-rat-0.12.jar -d "
-
-# generate the rat report
-# Ignore symlinks as RAT does not seem to understand them.
-$RAT $1 \
-  -e ".*" \
-  -e mman.h \
-  -e "*_generated.h" \
-  -e asan_symbolize.py \
-  -e cpplint.py \
-  -e pax_global_header \
-  -e clang_format_exclusions.txt \
-  -e ArrowExternalProject.cmake \
-  -e FindArrow.cmake \
-  > rat.txt
-cat rat.txt
-UNAPPROVED=`cat rat.txt  | grep "Unknown Licenses" | head -n 1 | cut -d " " -f 1`
-
-if [ "0" -eq "${UNAPPROVED}" ]; then
-  echo "No unnaproved licenses"
-else
-  echo "${UNAPPROVED} unapproved licences. Check rat report: rat.txt"
-  exit 1
-fi
-
-
diff --git a/dev/release/verify-release-candidate b/dev/release/verify-release-candidate
deleted file mode 100755
index 8555b8a..0000000
--- a/dev/release/verify-release-candidate
+++ /dev/null
@@ -1,97 +0,0 @@
-#!/usr/bin/env bash
-#
-# 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.
-#
-#
-# Downloads a release candidate and verifies that it passes binary
-# verification (signature and checksums) and test suites.
-#
-set -ex
-
-HERE=$(cd `dirname "${BASH_SOURCE[0]:-$0}"` && pwd)
-
-parquet_svn_dev_dist_url='https://dist.apache.org/repos/dist/dev/parquet'
-
-download_dist_file() {
-  curl -f -O ${parquet_svn_dev_dist_url}/$1
-}
-
-download_rc_file() {
-  download_dist_file apache-parquet-cpp-${verify_version}-rc${verify_rc_num}/$1
-}
-
-import_gpg_keys() {
-  download_dist_file KEYS
-  gpg --import KEYS
-}
-
-fetch_archive() {
-  local dist_name=$1
-  download_rc_file ${dist_name}.tar.gz
-  download_rc_file ${dist_name}.tar.gz.asc
-  download_rc_file ${dist_name}.tar.gz.md5
-  download_rc_file ${dist_name}.tar.gz.sha512
-  gpg --verify ${dist_name}.tar.gz.asc ${dist_name}.tar.gz
-  gpg --print-md MD5 ${dist_name}.tar.gz | diff - ${dist_name}.tar.gz.md5
-  if [ "$(uname)" == "Darwin" ]; then
-    shasum -a 512 ${dist_name}.tar.gz | diff - ${dist_name}.tar.gz.sha512
-  else
-    sha512sum ${dist_name}.tar.gz | diff - ${dist_name}.tar.gz.sha512
-  fi
-}
-
-run_tests() {
-  # Build
-  mkdir -p build
-  cd build
-  cmake ..
-  make -j5
-
-  # Test
-  export PARQUET_TEST_DATA=$(dirname $(pwd))/data
-  make unittest
-}
-
-setup_tempdir() {
-  cleanup() {
-    rm -fr "$TMPDIR"
-  }
-  trap cleanup EXIT
-  TMPDIR=$(mktemp -d -t "$1.XXXXX")
-}
-
-case $# in
-  2) verify_version="$1"
-     verify_rc_num="$2"
-     ;;
-
-  *) echo "Usage: $0 VERSION RC_NUM"
-     echo "Example to test 1.3.0-rc2: $0 1.3.0 2"
-     exit 1
-     ;;
-esac
-
-setup_tempdir "parquet-cpp-$verify_version"
-echo "Working in sandbox $TMPDIR"
-cd $TMPDIR
-
-import_gpg_keys
-
-dist_name="apache-parquet-cpp-${verify_version}"
-fetch_archive $dist_name
-tar xvzf ${dist_name}.tar.gz
-cd ${dist_name}
-run_tests
-
-echo 'Release candidate looks good!'
-exit 0
diff --git a/dev/release/verify-release-candidate.bat b/dev/release/verify-release-candidate.bat
deleted file mode 100644
index b5aaa8a..0000000
--- a/dev/release/verify-release-candidate.bat
+++ /dev/null
@@ -1,54 +0,0 @@
-@rem Licensed to the Apache Software Foundation (ASF) under one
-@rem or more contributor license agreements.  See the NOTICE file
-@rem distributed with this work for additional information
-@rem regarding copyright ownership.  The ASF licenses this file
-@rem to you under the Apache License, Version 2.0 (the
-@rem "License"); you may not use this file except in compliance
-@rem with the License.  You may obtain a copy of the License at
-@rem
-@rem   http://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing,
-@rem software distributed under the License is distributed on an
-@rem "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-@rem KIND, either express or implied.  See the License for the
-@rem specific language governing permissions and limitations
-@rem under the License.
-
-@rem Then run from the directory containing the RC tarball
-@rem
-@rem verify-release-candidate.bat apache-parquet-cpp-%VERSION%
-
-@echo on
-
-if not exist "C:\tmp\" mkdir C:\tmp
-if exist "C:\tmp\parquet-verify-release" rd C:\tmp\parquet-verify-release /s /q
-if not exist "C:\tmp\parquet-verify-release" mkdir C:\tmp\parquet-verify-release
-
-tar xvf %1.tar.gz -C "C:/tmp/"
-
-set GENERATOR=Visual Studio 14 2015 Win64
-set CONFIGURATION=release
-set PARQUET_SOURCE=C:\tmp\%1
-set INSTALL_DIR=C:\tmp\%1\install
-
-pushd %PARQUET_SOURCE%
-
-set PARQUET_TEST_DATA=%PARQUET_SOURCE%\data
-
-set PARQUET_HOME=%INSTALL_DIR%
-set PATH=%INSTALL_DIR%\bin;%PATH%
-
-mkdir build
-pushd build
-
-cmake -G "%GENERATOR%" ^
-      -DCMAKE_INSTALL_PREFIX=%PARQUET_HOME% ^
-      -DPARQUET_BOOST_USE_SHARED=OFF ^
-      -DCMAKE_BUILD_TYPE=%CONFIGURATION% ^
-      -DPARQUET_CXXFLAGS="/WX /MP" ^
-      ..  || exit /B
-cmake --build . --target INSTALL --config %CONFIGURATION%  || exit /B
-
-ctest -VV  || exit /B
-popd
diff --git a/docs/Windows.md b/docs/Windows.md
deleted file mode 100644
index 8de04f6..0000000
--- a/docs/Windows.md
+++ /dev/null
@@ -1,142 +0,0 @@
-<!---
-  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. See accompanying LICENSE file.
--->
-
-# Building parquet-cpp on Windows
-
-## Fast setup of building requirements with conda and conda-forge
-
-A convenient and tested way to set up thirdparty dependencies is to use the
-conda package manager.
-Please feel free to extend this document with others ways to setup
-development environment for parquet-cpp.
-
-### conda and package toolchain
-
-[Miniconda][1] is a minimal Python distribution including the conda package
-manager. To get started, download and install a 64-bit distribution.
-
-We recommend using packages from [conda-forge][2].
-Launch cmd.exe and run following to bootstrap a build environment:
-
-```shell
-conda create -n parquet-dev cmake git boost-cpp curl zlib snappy brotli thrift-cpp -c conda-forge
-```
-
-To allow cmake to pick up 3rd party dependencies, you should set
-`PARQUET_BUILD_TOOLCHAIN` environment variable to contain `Library` folder
-path of new created on previous step `parquet-dev` conda environment.
-For instance, if `Miniconda` was installed to default destination, `Library`
-folder path for `parquet-dev` conda environment will be as following:
-
-```shell
-C:\Users\YOUR_USER_NAME\Miniconda3\envs\parquet-dev\Library
-```
-
-As alternative to `PARQUET_BUILD_TOOLCHAIN`, it's possible to configure path
-to each 3rd party dependency separately by setting appropriate environment
-variable:
-
-`BOOST_ROOT` variable with path to `boost` installation  
-`THRIFT_HOME` variable with path to `thrift-cpp` installation  
-`SNAPPY_HOME` variable with path to `snappy` installation  
-`ZLIB_HOME` variable with path to `zlib` installation  
-`BROTLI_HOME` variable with path to `brotli` installation  
-`ARROW_HOME` variable with path to `arrow` installation
-
-### Customize static libraries names lookup of 3rd party dependencies 
-
-If you decided to use pre-built 3rd party dependencies libs, it's possible to
-configure parquet-cpp cmake build script to search for customized names of 3rd
-party static libs.
-
-`zlib`. Pass `-DPARQUET_ZLIB_VENDORED=OFF` to enable lookup of custom zlib
-build. Set `ZLIB_HOME` environment variable. Pass
-`-DZLIB_MSVC_STATIC_LIB_SUFFIX=%ZLIB_SUFFIX%` to link with z%ZLIB_SUFFIX%.lib
-
-`arrow`. Set `ARROW_HOME` environment variable. Pass
-`-DARROW_MSVC_STATIC_LIB_SUFFIX=%ARROW_SUFFIX%` to link with
-arrow%ARROW_SUFFIX%.lib
-
-`brotli`. Set `BROTLY_HOME` environment variable. Pass
-`-DBROTLI_MSVC_STATIC_LIB_SUFFIX=%BROTLI_SUFFIX%` to link with
-brotli*%BROTLI_SUFFIX%.lib.
-
-`snappy`. Set `SNAPPY_HOME` environment variable. Pass
-`-DSNAPPY_MSVC_STATIC_LIB_SUFFIX=%SNAPPY_SUFFIX%` to link with
-snappy%SNAPPY_SUFFIX%.lib.
-
-`thrift`. Set `THRIFT_HOME` environment variable. Pass
-`-DTHRIFT_MSVC_STATIC_LIB_SUFFIX=%THRIFT_SUFFIX%` to link with
-thrift*%THRIFT_SUFFIX%.lib.
-
-### Visual Studio
-
-Microsoft provides the free Visual Studio Community edition. Once you have
-Visual Studio installed, you should configure cmd.exe environment to be able
-to find Visual Studio's build toolchain by running following commands:
-
-#### Visual Studio 2015
-
-```"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64```
-
-#### Visual Studio 2017
-
-```"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat" -arch=amd64```
-
-It's easiest to configure a console emulator like [cmder][3] to automatically
-launch this when starting a new development console.
-
-## Building with NMake
-
-Activate your conda build environment:
-
-```
-activate parquet-dev
-```
-
-Change working directory in cmd.exe to the root directory of parquet-cpp and
-do an out of source build using `nmake`:
-
-```
-cd %PARQUET_ROOT_SOURCES_DIRECTORY%
-mkdir build
-cd build
-cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release ..
-nmake
-```
-
-## Building with Visual Studio cmake generator
-
-Activate your conda build environment:
-
-```
-activate parquet-dev
-```
-
-Change working directory in cmd.exe to the root directory of parquet-cpp and
-do an out of source build:
-
-```
-cd %PARQUET_ROOT_SOURCES_DIRECTORY%
-mkdir build
-cd build
-cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_BUILD_TYPE=Release ..
-cmake --build . --config Release
-```
-
-When using conda, only release builds are currently supported.
-
-[1]: https://conda.io/miniconda.html
-[2]: https://conda-forge.github.io/
-[3]: http://cmder.net/
\ No newline at end of file
diff --git a/examples/low-level-api/CMakeLists.txt b/examples/low-level-api/CMakeLists.txt
deleted file mode 100644
index 64ba110..0000000
--- a/examples/low-level-api/CMakeLists.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-# 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.
-
-if (PARQUET_BUILD_EXECUTABLES)
-  add_executable(reader-writer reader-writer.cc)
-  add_executable(reader-writer2 reader-writer2.cc)
-  target_include_directories(reader-writer PRIVATE .)
-  target_include_directories(reader-writer2 PRIVATE .)
-  target_link_libraries(reader-writer parquet_static)
-  target_link_libraries(reader-writer2 parquet_static)
-endif()
diff --git a/examples/low-level-api/reader-writer.cc b/examples/low-level-api/reader-writer.cc
deleted file mode 100644
index 09cd137..0000000
--- a/examples/low-level-api/reader-writer.cc
+++ /dev/null
@@ -1,409 +0,0 @@
-// 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.
-
-#include <cassert>
-#include <fstream>
-#include <iostream>
-#include <memory>
-
-#include <reader_writer.h>
-
-/*
- * This example describes writing and reading Parquet Files in C++ and serves as a
- * reference to the API.
- * The file contains all the physical data types supported by Parquet.
- * This example uses the RowGroupWriter API that supports writing RowGroups optimized for
- *memory consumption
- **/
-
-/* Parquet is a structured columnar file format
- * Parquet File = "Parquet data" + "Parquet Metadata"
- * "Parquet data" is simply a vector of RowGroups. Each RowGroup is a batch of rows in a
- * columnar layout
- * "Parquet Metadata" contains the "file schema" and attributes of the RowGroups and their
- * Columns
- * "file schema" is a tree where each node is either a primitive type (leaf nodes) or a
- * complex (nested) type (internal nodes)
- * For specific details, please refer the format here:
- * https://github.com/apache/parquet-format/blob/master/LogicalTypes.md
- **/
-
-constexpr int NUM_ROWS_PER_ROW_GROUP = 500;
-const char PARQUET_FILENAME[] = "parquet_cpp_example.parquet";
-
-int main(int argc, char** argv) {
-  /**********************************************************************************
-                             PARQUET WRITER EXAMPLE
-  **********************************************************************************/
-  // parquet::REQUIRED fields do not need definition and repetition level values
-  // parquet::OPTIONAL fields require only definition level values
-  // parquet::REPEATED fields require both definition and repetition level values
-  try {
-    // Create a local file output stream instance.
-    using FileClass = ::arrow::io::FileOutputStream;
-    std::shared_ptr<FileClass> out_file;
-    PARQUET_THROW_NOT_OK(FileClass::Open(PARQUET_FILENAME, &out_file));
-
-    // Setup the parquet schema
-    std::shared_ptr<GroupNode> schema = SetupSchema();
-
-    // Add writer properties
-    parquet::WriterProperties::Builder builder;
-    builder.compression(parquet::Compression::SNAPPY);
-    std::shared_ptr<parquet::WriterProperties> props = builder.build();
-
-    // Create a ParquetFileWriter instance
-    std::shared_ptr<parquet::ParquetFileWriter> file_writer =
-        parquet::ParquetFileWriter::Open(out_file, schema, props);
-
-    // Append a RowGroup with a specific number of rows.
-    parquet::RowGroupWriter* rg_writer = file_writer->AppendRowGroup();
-
-    // Write the Bool column
-    parquet::BoolWriter* bool_writer =
-        static_cast<parquet::BoolWriter*>(rg_writer->NextColumn());
-    for (int i = 0; i < NUM_ROWS_PER_ROW_GROUP; i++) {
-      bool value = ((i % 2) == 0) ? true : false;
-      bool_writer->WriteBatch(1, nullptr, nullptr, &value);
-    }
-
-    // Write the Int32 column
-    parquet::Int32Writer* int32_writer =
-        static_cast<parquet::Int32Writer*>(rg_writer->NextColumn());
-    for (int i = 0; i < NUM_ROWS_PER_ROW_GROUP; i++) {
-      int32_t value = i;
-      int32_writer->WriteBatch(1, nullptr, nullptr, &value);
-    }
-
-    // Write the Int64 column. Each row has repeats twice.
-    parquet::Int64Writer* int64_writer =
-        static_cast<parquet::Int64Writer*>(rg_writer->NextColumn());
-    for (int i = 0; i < 2 * NUM_ROWS_PER_ROW_GROUP; i++) {
-      int64_t value = i * 1000 * 1000;
-      value *= 1000 * 1000;
-      int16_t definition_level = 1;
-      int16_t repetition_level = 0;
-      if ((i % 2) == 0) {
-        repetition_level = 1;  // start of a new record
-      }
-      int64_writer->WriteBatch(1, &definition_level, &repetition_level, &value);
-    }
-
-    // Write the INT96 column.
-    parquet::Int96Writer* int96_writer =
-        static_cast<parquet::Int96Writer*>(rg_writer->NextColumn());
-    for (int i = 0; i < NUM_ROWS_PER_ROW_GROUP; i++) {
-      parquet::Int96 value;
-      value.value[0] = i;
-      value.value[1] = i + 1;
-      value.value[2] = i + 2;
-      int96_writer->WriteBatch(1, nullptr, nullptr, &value);
-    }
-
-    // Write the Float column
-    parquet::FloatWriter* float_writer =
-        static_cast<parquet::FloatWriter*>(rg_writer->NextColumn());
-    for (int i = 0; i < NUM_ROWS_PER_ROW_GROUP; i++) {
-      float value = static_cast<float>(i) * 1.1f;
-      float_writer->WriteBatch(1, nullptr, nullptr, &value);
-    }
-
-    // Write the Double column
-    parquet::DoubleWriter* double_writer =
-        static_cast<parquet::DoubleWriter*>(rg_writer->NextColumn());
-    for (int i = 0; i < NUM_ROWS_PER_ROW_GROUP; i++) {
-      double value = i * 1.1111111;
-      double_writer->WriteBatch(1, nullptr, nullptr, &value);
-    }
-
-    // Write the ByteArray column. Make every alternate values NULL
-    parquet::ByteArrayWriter* ba_writer =
-        static_cast<parquet::ByteArrayWriter*>(rg_writer->NextColumn());
-    for (int i = 0; i < NUM_ROWS_PER_ROW_GROUP; i++) {
-      parquet::ByteArray value;
-      char hello[FIXED_LENGTH] = "parquet";
-      hello[7] = static_cast<char>(static_cast<int>('0') + i / 100);
-      hello[8] = static_cast<char>(static_cast<int>('0') + (i / 10) % 10);
-      hello[9] = static_cast<char>(static_cast<int>('0') + i % 10);
-      if (i % 2 == 0) {
-        int16_t definition_level = 1;
-        value.ptr = reinterpret_cast<const uint8_t*>(&hello[0]);
-        value.len = FIXED_LENGTH;
-        ba_writer->WriteBatch(1, &definition_level, nullptr, &value);
-      } else {
-        int16_t definition_level = 0;
-        ba_writer->WriteBatch(1, &definition_level, nullptr, nullptr);
-      }
-    }
-
-    // Write the FixedLengthByteArray column
-    parquet::FixedLenByteArrayWriter* flba_writer =
-        static_cast<parquet::FixedLenByteArrayWriter*>(rg_writer->NextColumn());
-    for (int i = 0; i < NUM_ROWS_PER_ROW_GROUP; i++) {
-      parquet::FixedLenByteArray value;
-      char v = static_cast<char>(i);
-      char flba[FIXED_LENGTH] = {v, v, v, v, v, v, v, v, v, v};
-      value.ptr = reinterpret_cast<const uint8_t*>(&flba[0]);
-
-      flba_writer->WriteBatch(1, nullptr, nullptr, &value);
-    }
-
-    // Close the ParquetFileWriter
-    file_writer->Close();
-
-    // Write the bytes to file
-    DCHECK(out_file->Close().ok());
-  } catch (const std::exception& e) {
-    std::cerr << "Parquet write error: " << e.what() << std::endl;
-    return -1;
-  }
-
-  /**********************************************************************************
-                             PARQUET READER EXAMPLE
-  **********************************************************************************/
-
-  try {
-    // Create a ParquetReader instance
-    std::unique_ptr<parquet::ParquetFileReader> parquet_reader =
-        parquet::ParquetFileReader::OpenFile(PARQUET_FILENAME, false);
-
-    // Get the File MetaData
-    std::shared_ptr<parquet::FileMetaData> file_metadata = parquet_reader->metadata();
-
-    // Get the number of RowGroups
-    int num_row_groups = file_metadata->num_row_groups();
-    assert(num_row_groups == 1);
-
-    // Get the number of Columns
-    int num_columns = file_metadata->num_columns();
-    assert(num_columns == 8);
-
-    // Iterate over all the RowGroups in the file
-    for (int r = 0; r < num_row_groups; ++r) {
-      // Get the RowGroup Reader
-      std::shared_ptr<parquet::RowGroupReader> row_group_reader =
-          parquet_reader->RowGroup(r);
-
-      int64_t values_read = 0;
-      int64_t rows_read = 0;
-      int16_t definition_level;
-      int16_t repetition_level;
-      int i;
-      std::shared_ptr<parquet::ColumnReader> column_reader;
-
-      // Get the Column Reader for the boolean column
-      column_reader = row_group_reader->Column(0);
-      parquet::BoolReader* bool_reader =
-          static_cast<parquet::BoolReader*>(column_reader.get());
-
-      // Read all the rows in the column
-      i = 0;
-      while (bool_reader->HasNext()) {
-        bool value;
-        // Read one value at a time. The number of rows read is returned. values_read
-        // contains the number of non-null rows
-        rows_read = bool_reader->ReadBatch(1, nullptr, nullptr, &value, &values_read);
-        // Ensure only one value is read
-        assert(rows_read == 1);
-        // There are no NULL values in the rows written
-        assert(values_read == 1);
-        // Verify the value written
-        bool expected_value = ((i % 2) == 0) ? true : false;
-        assert(value == expected_value);
-        i++;
-      }
-
-      // Get the Column Reader for the Int32 column
-      column_reader = row_group_reader->Column(1);
-      parquet::Int32Reader* int32_reader =
-          static_cast<parquet::Int32Reader*>(column_reader.get());
-      // Read all the rows in the column
-      i = 0;
-      while (int32_reader->HasNext()) {
-        int32_t value;
-        // Read one value at a time. The number of rows read is returned. values_read
-        // contains the number of non-null rows
-        rows_read = int32_reader->ReadBatch(1, nullptr, nullptr, &value, &values_read);
-        // Ensure only one value is read
-        assert(rows_read == 1);
-        // There are no NULL values in the rows written
-        assert(values_read == 1);
-        // Verify the value written
-        assert(value == i);
-        i++;
-      }
-
-      // Get the Column Reader for the Int64 column
-      column_reader = row_group_reader->Column(2);
-      parquet::Int64Reader* int64_reader =
-          static_cast<parquet::Int64Reader*>(column_reader.get());
-      // Read all the rows in the column
-      i = 0;
-      while (int64_reader->HasNext()) {
-        int64_t value;
-        // Read one value at a time. The number of rows read is returned. values_read
-        // contains the number of non-null rows
-        rows_read = int64_reader->ReadBatch(1, &definition_level, &repetition_level,
-                                            &value, &values_read);
-        // Ensure only one value is read
-        assert(rows_read == 1);
-        // There are no NULL values in the rows written
-        assert(values_read == 1);
-        // Verify the value written
-        int64_t expected_value = i * 1000 * 1000;
-        expected_value *= 1000 * 1000;
-        assert(value == expected_value);
-        if ((i % 2) == 0) {
-          assert(repetition_level == 1);
-        } else {
-          assert(repetition_level == 0);
-        }
-        i++;
-      }
-
-      // Get the Column Reader for the Int96 column
-      column_reader = row_group_reader->Column(3);
-      parquet::Int96Reader* int96_reader =
-          static_cast<parquet::Int96Reader*>(column_reader.get());
-      // Read all the rows in the column
-      i = 0;
-      while (int96_reader->HasNext()) {
-        parquet::Int96 value;
-        // Read one value at a time. The number of rows read is returned. values_read
-        // contains the number of non-null rows
-        rows_read = int96_reader->ReadBatch(1, nullptr, nullptr, &value, &values_read);
-        // Ensure only one value is read
-        assert(rows_read == 1);
-        // There are no NULL values in the rows written
-        assert(values_read == 1);
-        // Verify the value written
-        parquet::Int96 expected_value;
-        expected_value.value[0] = i;
-        expected_value.value[1] = i + 1;
-        expected_value.value[2] = i + 2;
-        for (int j = 0; j < 3; j++) {
-          assert(value.value[j] == expected_value.value[j]);
-        }
-        i++;
-      }
-
-      // Get the Column Reader for the Float column
-      column_reader = row_group_reader->Column(4);
-      parquet::FloatReader* float_reader =
-          static_cast<parquet::FloatReader*>(column_reader.get());
-      // Read all the rows in the column
-      i = 0;
-      while (float_reader->HasNext()) {
-        float value;
-        // Read one value at a time. The number of rows read is returned. values_read
-        // contains the number of non-null rows
-        rows_read = float_reader->ReadBatch(1, nullptr, nullptr, &value, &values_read);
-        // Ensure only one value is read
-        assert(rows_read == 1);
-        // There are no NULL values in the rows written
-        assert(values_read == 1);
-        // Verify the value written
-        float expected_value = static_cast<float>(i) * 1.1f;
-        assert(value == expected_value);
-        i++;
-      }
-
-      // Get the Column Reader for the Double column
-      column_reader = row_group_reader->Column(5);
-      parquet::DoubleReader* double_reader =
-          static_cast<parquet::DoubleReader*>(column_reader.get());
-      // Read all the rows in the column
-      i = 0;
-      while (double_reader->HasNext()) {
-        double value;
-        // Read one value at a time. The number of rows read is returned. values_read
-        // contains the number of non-null rows
-        rows_read = double_reader->ReadBatch(1, nullptr, nullptr, &value, &values_read);
-        // Ensure only one value is read
-        assert(rows_read == 1);
-        // There are no NULL values in the rows written
-        assert(values_read == 1);
-        // Verify the value written
-        double expected_value = i * 1.1111111;
-        assert(value == expected_value);
-        i++;
-      }
-
-      // Get the Column Reader for the ByteArray column
-      column_reader = row_group_reader->Column(6);
-      parquet::ByteArrayReader* ba_reader =
-          static_cast<parquet::ByteArrayReader*>(column_reader.get());
-      // Read all the rows in the column
-      i = 0;
-      while (ba_reader->HasNext()) {
-        parquet::ByteArray value;
-        // Read one value at a time. The number of rows read is returned. values_read
-        // contains the number of non-null rows
-        rows_read =
-            ba_reader->ReadBatch(1, &definition_level, nullptr, &value, &values_read);
-        // Ensure only one value is read
-        assert(rows_read == 1);
-        // Verify the value written
-        char expected_value[FIXED_LENGTH] = "parquet";
-        expected_value[7] = static_cast<char>('0' + i / 100);
-        expected_value[8] = static_cast<char>('0' + (i / 10) % 10);
-        expected_value[9] = static_cast<char>('0' + i % 10);
-        if (i % 2 == 0) {  // only alternate values exist
-          // There are no NULL values in the rows written
-          assert(values_read == 1);
-          assert(value.len == FIXED_LENGTH);
-          assert(memcmp(value.ptr, &expected_value[0], FIXED_LENGTH) == 0);
-          assert(definition_level == 1);
-        } else {
-          // There are NULL values in the rows written
-          assert(values_read == 0);
-          assert(definition_level == 0);
-        }
-        i++;
-      }
-
-      // Get the Column Reader for the FixedLengthByteArray column
-      column_reader = row_group_reader->Column(7);
-      parquet::FixedLenByteArrayReader* flba_reader =
-          static_cast<parquet::FixedLenByteArrayReader*>(column_reader.get());
-      // Read all the rows in the column
-      i = 0;
-      while (flba_reader->HasNext()) {
-        parquet::FixedLenByteArray value;
-        // Read one value at a time. The number of rows read is returned. values_read
-        // contains the number of non-null rows
-        rows_read = flba_reader->ReadBatch(1, nullptr, nullptr, &value, &values_read);
-        // Ensure only one value is read
-        assert(rows_read == 1);
-        // There are no NULL values in the rows written
-        assert(values_read == 1);
-        // Verify the value written
-        char v = static_cast<char>(i);
-        char expected_value[FIXED_LENGTH] = {v, v, v, v, v, v, v, v, v, v};
-        assert(memcmp(value.ptr, &expected_value[0], FIXED_LENGTH) == 0);
-        i++;
-      }
-    }
-  } catch (const std::exception& e) {
-    std::cerr << "Parquet read error: " << e.what() << std::endl;
-    return -1;
-  }
-
-  std::cout << "Parquet Writing and Reading Complete" << std::endl;
-
-  return 0;
-}
diff --git a/examples/low-level-api/reader-writer2.cc b/examples/low-level-api/reader-writer2.cc
deleted file mode 100644
index dded5fa..0000000
--- a/examples/low-level-api/reader-writer2.cc
+++ /dev/null
@@ -1,430 +0,0 @@
-// 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.
-
-#include <cassert>
-#include <fstream>
-#include <iostream>
-#include <memory>
-
-#include <reader_writer.h>
-
-/*
- * This example describes writing and reading Parquet Files in C++ and serves as a
- * reference to the API.
- * The file contains all the physical data types supported by Parquet.
- * This example uses the RowGroupWriter API that supports writing RowGroups based on a
- *certain size
- **/
-
-/* Parquet is a structured columnar file format
- * Parquet File = "Parquet data" + "Parquet Metadata"
- * "Parquet data" is simply a vector of RowGroups. Each RowGroup is a batch of rows in a
- * columnar layout
- * "Parquet Metadata" contains the "file schema" and attributes of the RowGroups and their
- * Columns
- * "file schema" is a tree where each node is either a primitive type (leaf nodes) or a
- * complex (nested) type (internal nodes)
- * For specific details, please refer the format here:
- * https://github.com/apache/parquet-format/blob/master/LogicalTypes.md
- **/
-
-constexpr int NUM_ROWS = 2500000;
-constexpr int64_t ROW_GROUP_SIZE = 16 * 1024 * 1024;  // 16 MB
-const char PARQUET_FILENAME[] = "parquet_cpp_example2.parquet";
-
-int main(int argc, char** argv) {
-  /**********************************************************************************
-                             PARQUET WRITER EXAMPLE
-  **********************************************************************************/
-  // parquet::REQUIRED fields do not need definition and repetition level values
-  // parquet::OPTIONAL fields require only definition level values
-  // parquet::REPEATED fields require both definition and repetition level values
-  try {
-    // Create a local file output stream instance.
-    using FileClass = ::arrow::io::FileOutputStream;
-    std::shared_ptr<FileClass> out_file;
-    PARQUET_THROW_NOT_OK(FileClass::Open(PARQUET_FILENAME, &out_file));
-
-    // Setup the parquet schema
-    std::shared_ptr<GroupNode> schema = SetupSchema();
-
-    // Add writer properties
-    parquet::WriterProperties::Builder builder;
-    builder.compression(parquet::Compression::SNAPPY);
-    std::shared_ptr<parquet::WriterProperties> props = builder.build();
-
-    // Create a ParquetFileWriter instance
-    std::shared_ptr<parquet::ParquetFileWriter> file_writer =
-        parquet::ParquetFileWriter::Open(out_file, schema, props);
-
-    // Append a BufferedRowGroup to keep the RowGroup open until a certain size
-    parquet::RowGroupWriter* rg_writer = file_writer->AppendBufferedRowGroup();
-
-    int num_columns = file_writer->num_columns();
-    std::vector<int64_t> buffered_values_estimate(num_columns, 0);
-    for (int i = 0; i < NUM_ROWS; i++) {
-      int64_t estimated_bytes = 0;
-      // Get the estimated size of the values that are not written to a page yet
-      for (int n = 0; n < num_columns; n++) {
-        estimated_bytes += buffered_values_estimate[n];
-      }
-
-      // We need to consider the compressed pages
-      // as well as the values that are not compressed yet
-      if ((rg_writer->total_bytes_written() + rg_writer->total_compressed_bytes() +
-           estimated_bytes) > ROW_GROUP_SIZE) {
-        rg_writer->Close();
-        std::fill(buffered_values_estimate.begin(), buffered_values_estimate.end(), 0);
-        rg_writer = file_writer->AppendBufferedRowGroup();
-      }
-
-      int col_id = 0;
-      // Write the Bool column
-      parquet::BoolWriter* bool_writer =
-          static_cast<parquet::BoolWriter*>(rg_writer->column(col_id));
-      bool bool_value = ((i % 2) == 0) ? true : false;
-      bool_writer->WriteBatch(1, nullptr, nullptr, &bool_value);
-      buffered_values_estimate[col_id] = bool_writer->EstimatedBufferedValueBytes();
-
-      // Write the Int32 column
-      col_id++;
-      parquet::Int32Writer* int32_writer =
-          static_cast<parquet::Int32Writer*>(rg_writer->column(col_id));
-      int32_t int32_value = i;
-      int32_writer->WriteBatch(1, nullptr, nullptr, &int32_value);
-      buffered_values_estimate[col_id] = int32_writer->EstimatedBufferedValueBytes();
-
-      // Write the Int64 column. Each row has repeats twice.
-      col_id++;
-      parquet::Int64Writer* int64_writer =
-          static_cast<parquet::Int64Writer*>(rg_writer->column(col_id));
-      int64_t int64_value1 = 2 * i;
-      int16_t definition_level = 1;
-      int16_t repetition_level = 0;
-      int64_writer->WriteBatch(1, &definition_level, &repetition_level, &int64_value1);
-      int64_t int64_value2 = (2 * i + 1);
-      repetition_level = 1;  // start of a new record
-      int64_writer->WriteBatch(1, &definition_level, &repetition_level, &int64_value2);
-      buffered_values_estimate[col_id] = int64_writer->EstimatedBufferedValueBytes();
-
-      // Write the INT96 column.
-      col_id++;
-      parquet::Int96Writer* int96_writer =
-          static_cast<parquet::Int96Writer*>(rg_writer->column(col_id));
-      parquet::Int96 int96_value;
-      int96_value.value[0] = i;
-      int96_value.value[1] = i + 1;
-      int96_value.value[2] = i + 2;
-      int96_writer->WriteBatch(1, nullptr, nullptr, &int96_value);
-      buffered_values_estimate[col_id] = int96_writer->EstimatedBufferedValueBytes();
-
-      // Write the Float column
-      col_id++;
-      parquet::FloatWriter* float_writer =
-          static_cast<parquet::FloatWriter*>(rg_writer->column(col_id));
-      float float_value = static_cast<float>(i) * 1.1f;
-      float_writer->WriteBatch(1, nullptr, nullptr, &float_value);
-      buffered_values_estimate[col_id] = float_writer->EstimatedBufferedValueBytes();
-
-      // Write the Double column
-      col_id++;
-      parquet::DoubleWriter* double_writer =
-          static_cast<parquet::DoubleWriter*>(rg_writer->column(col_id));
-      double double_value = i * 1.1111111;
-      double_writer->WriteBatch(1, nullptr, nullptr, &double_value);
-      buffered_values_estimate[col_id] = double_writer->EstimatedBufferedValueBytes();
-
-      // Write the ByteArray column. Make every alternate values NULL
-      col_id++;
-      parquet::ByteArrayWriter* ba_writer =
-          static_cast<parquet::ByteArrayWriter*>(rg_writer->column(col_id));
-      parquet::ByteArray ba_value;
-      char hello[FIXED_LENGTH] = "parquet";
-      hello[7] = static_cast<char>(static_cast<int>('0') + i / 100);
-      hello[8] = static_cast<char>(static_cast<int>('0') + (i / 10) % 10);
-      hello[9] = static_cast<char>(static_cast<int>('0') + i % 10);
-      if (i % 2 == 0) {
-        int16_t definition_level = 1;
-        ba_value.ptr = reinterpret_cast<const uint8_t*>(&hello[0]);
-        ba_value.len = FIXED_LENGTH;
-        ba_writer->WriteBatch(1, &definition_level, nullptr, &ba_value);
-      } else {
-        int16_t definition_level = 0;
-        ba_writer->WriteBatch(1, &definition_level, nullptr, nullptr);
-      }
-      buffered_values_estimate[col_id] = ba_writer->EstimatedBufferedValueBytes();
-
-      // Write the FixedLengthByteArray column
-      col_id++;
-      parquet::FixedLenByteArrayWriter* flba_writer =
-          static_cast<parquet::FixedLenByteArrayWriter*>(rg_writer->column(col_id));
-      parquet::FixedLenByteArray flba_value;
-      char v = static_cast<char>(i);
-      char flba[FIXED_LENGTH] = {v, v, v, v, v, v, v, v, v, v};
-      flba_value.ptr = reinterpret_cast<const uint8_t*>(&flba[0]);
-
-      flba_writer->WriteBatch(1, nullptr, nullptr, &flba_value);
-      buffered_values_estimate[col_id] = flba_writer->EstimatedBufferedValueBytes();
-    }
-
-    // Close the RowGroupWriter
-    rg_writer->Close();
-    // Close the ParquetFileWriter
-    file_writer->Close();
-
-    // Write the bytes to file
-    DCHECK(out_file->Close().ok());
-  } catch (const std::exception& e) {
-    std::cerr << "Parquet write error: " << e.what() << std::endl;
-    return -1;
-  }
-
-  /**********************************************************************************
-                             PARQUET READER EXAMPLE
-  **********************************************************************************/
-
-  try {
-    // Create a ParquetReader instance
-    std::unique_ptr<parquet::ParquetFileReader> parquet_reader =
-        parquet::ParquetFileReader::OpenFile(PARQUET_FILENAME, false);
-
-    // Get the File MetaData
-    std::shared_ptr<parquet::FileMetaData> file_metadata = parquet_reader->metadata();
-
-    int num_row_groups = file_metadata->num_row_groups();
-
-    // Get the number of Columns
-    int num_columns = file_metadata->num_columns();
-    assert(num_columns == 8);
-
-    std::vector<int> col_row_counts(num_columns, 0);
-
-    // Iterate over all the RowGroups in the file
-    for (int r = 0; r < num_row_groups; ++r) {
-      // Get the RowGroup Reader
-      std::shared_ptr<parquet::RowGroupReader> row_group_reader =
-          parquet_reader->RowGroup(r);
-
-      assert(row_group_reader->metadata()->total_byte_size() < ROW_GROUP_SIZE);
-
-      int64_t values_read = 0;
-      int64_t rows_read = 0;
-      int16_t definition_level;
-      int16_t repetition_level;
-      std::shared_ptr<parquet::ColumnReader> column_reader;
-      int col_id = 0;
-
-      // Get the Column Reader for the boolean column
-      column_reader = row_group_reader->Column(col_id);
-      parquet::BoolReader* bool_reader =
-          static_cast<parquet::BoolReader*>(column_reader.get());
-
-      // Read all the rows in the column
-      while (bool_reader->HasNext()) {
-        bool value;
-        // Read one value at a time. The number of rows read is returned. values_read
-        // contains the number of non-null rows
-        rows_read = bool_reader->ReadBatch(1, nullptr, nullptr, &value, &values_read);
-        // Ensure only one value is read
-        assert(rows_read == 1);
-        // There are no NULL values in the rows written
-        assert(values_read == 1);
-        // Verify the value written
-        bool expected_value = ((col_row_counts[col_id] % 2) == 0) ? true : false;
-        assert(value == expected_value);
-        col_row_counts[col_id]++;
-      }
-
-      // Get the Column Reader for the Int32 column
-      col_id++;
-      column_reader = row_group_reader->Column(col_id);
-      parquet::Int32Reader* int32_reader =
-          static_cast<parquet::Int32Reader*>(column_reader.get());
-      // Read all the rows in the column
-      while (int32_reader->HasNext()) {
-        int32_t value;
-        // Read one value at a time. The number of rows read is returned. values_read
-        // contains the number of non-null rows
-        rows_read = int32_reader->ReadBatch(1, nullptr, nullptr, &value, &values_read);
-        // Ensure only one value is read
-        assert(rows_read == 1);
-        // There are no NULL values in the rows written
-        assert(values_read == 1);
-        // Verify the value written
-        assert(value == col_row_counts[col_id]);
-        col_row_counts[col_id]++;
-      }
-
-      // Get the Column Reader for the Int64 column
-      col_id++;
-      column_reader = row_group_reader->Column(col_id);
-      parquet::Int64Reader* int64_reader =
-          static_cast<parquet::Int64Reader*>(column_reader.get());
-      // Read all the rows in the column
-      while (int64_reader->HasNext()) {
-        int64_t value;
-        // Read one value at a time. The number of rows read is returned. values_read
-        // contains the number of non-null rows
-        rows_read = int64_reader->ReadBatch(1, &definition_level, &repetition_level,
-                                            &value, &values_read);
-        // Ensure only one value is read
-        assert(rows_read == 1);
-        // There are no NULL values in the rows written
-        assert(values_read == 1);
-        // Verify the value written
-        int64_t expected_value = col_row_counts[col_id];
-        assert(value == expected_value);
-        if ((col_row_counts[col_id] % 2) == 0) {
-          assert(repetition_level == 0);
-        } else {
-          assert(repetition_level == 1);
-        }
-        col_row_counts[col_id]++;
-      }
-
-      // Get the Column Reader for the Int96 column
-      col_id++;
-      column_reader = row_group_reader->Column(col_id);
-      parquet::Int96Reader* int96_reader =
-          static_cast<parquet::Int96Reader*>(column_reader.get());
-      // Read all the rows in the column
-      while (int96_reader->HasNext()) {
-        parquet::Int96 value;
-        // Read one value at a time. The number of rows read is returned. values_read
-        // contains the number of non-null rows
-        rows_read = int96_reader->ReadBatch(1, nullptr, nullptr, &value, &values_read);
-        // Ensure only one value is read
-        assert(rows_read == 1);
-        // There are no NULL values in the rows written
-        assert(values_read == 1);
-        // Verify the value written
-        parquet::Int96 expected_value;
-        expected_value.value[0] = col_row_counts[col_id];
-        expected_value.value[1] = col_row_counts[col_id] + 1;
-        expected_value.value[2] = col_row_counts[col_id] + 2;
-        for (int j = 0; j < 3; j++) {
-          assert(value.value[j] == expected_value.value[j]);
-        }
-        col_row_counts[col_id]++;
-      }
-
-      // Get the Column Reader for the Float column
-      col_id++;
-      column_reader = row_group_reader->Column(col_id);
-      parquet::FloatReader* float_reader =
-          static_cast<parquet::FloatReader*>(column_reader.get());
-      // Read all the rows in the column
-      while (float_reader->HasNext()) {
-        float value;
-        // Read one value at a time. The number of rows read is returned. values_read
-        // contains the number of non-null rows
-        rows_read = float_reader->ReadBatch(1, nullptr, nullptr, &value, &values_read);
-        // Ensure only one value is read
-        assert(rows_read == 1);
-        // There are no NULL values in the rows written
-        assert(values_read == 1);
-        // Verify the value written
-        float expected_value = static_cast<float>(col_row_counts[col_id]) * 1.1f;
-        assert(value == expected_value);
-        col_row_counts[col_id]++;
-      }
-
-      // Get the Column Reader for the Double column
-      col_id++;
-      column_reader = row_group_reader->Column(col_id);
-      parquet::DoubleReader* double_reader =
-          static_cast<parquet::DoubleReader*>(column_reader.get());
-      // Read all the rows in the column
-      while (double_reader->HasNext()) {
-        double value;
-        // Read one value at a time. The number of rows read is returned. values_read
-        // contains the number of non-null rows
-        rows_read = double_reader->ReadBatch(1, nullptr, nullptr, &value, &values_read);
-        // Ensure only one value is read
-        assert(rows_read == 1);
-        // There are no NULL values in the rows written
-        assert(values_read == 1);
-        // Verify the value written
-        double expected_value = col_row_counts[col_id] * 1.1111111;
-        assert(value == expected_value);
-        col_row_counts[col_id]++;
-      }
-
-      // Get the Column Reader for the ByteArray column
-      col_id++;
-      column_reader = row_group_reader->Column(col_id);
-      parquet::ByteArrayReader* ba_reader =
-          static_cast<parquet::ByteArrayReader*>(column_reader.get());
-      // Read all the rows in the column
-      while (ba_reader->HasNext()) {
-        parquet::ByteArray value;
-        // Read one value at a time. The number of rows read is returned. values_read
-        // contains the number of non-null rows
-        rows_read =
-            ba_reader->ReadBatch(1, &definition_level, nullptr, &value, &values_read);
-        // Ensure only one value is read
-        assert(rows_read == 1);
-        // Verify the value written
-        char expected_value[FIXED_LENGTH] = "parquet";
-        expected_value[7] = static_cast<char>('0' + col_row_counts[col_id] / 100);
-        expected_value[8] = static_cast<char>('0' + (col_row_counts[col_id] / 10) % 10);
-        expected_value[9] = static_cast<char>('0' + col_row_counts[col_id] % 10);
-        if (col_row_counts[col_id] % 2 == 0) {  // only alternate values exist
-          // There are no NULL values in the rows written
-          assert(values_read == 1);
-          assert(value.len == FIXED_LENGTH);
-          assert(memcmp(value.ptr, &expected_value[0], FIXED_LENGTH) == 0);
-          assert(definition_level == 1);
-        } else {
-          // There are NULL values in the rows written
-          assert(values_read == 0);
-          assert(definition_level == 0);
-        }
-        col_row_counts[col_id]++;
-      }
-
-      // Get the Column Reader for the FixedLengthByteArray column
-      col_id++;
-      column_reader = row_group_reader->Column(col_id);
-      parquet::FixedLenByteArrayReader* flba_reader =
-          static_cast<parquet::FixedLenByteArrayReader*>(column_reader.get());
-      // Read all the rows in the column
-      while (flba_reader->HasNext()) {
-        parquet::FixedLenByteArray value;
-        // Read one value at a time. The number of rows read is returned. values_read
-        // contains the number of non-null rows
-        rows_read = flba_reader->ReadBatch(1, nullptr, nullptr, &value, &values_read);
-        // Ensure only one value is read
-        assert(rows_read == 1);
-        // There are no NULL values in the rows written
-        assert(values_read == 1);
-        // Verify the value written
-        char v = static_cast<char>(col_row_counts[col_id]);
-        char expected_value[FIXED_LENGTH] = {v, v, v, v, v, v, v, v, v, v};
-        assert(memcmp(value.ptr, &expected_value[0], FIXED_LENGTH) == 0);
-        col_row_counts[col_id]++;
-      }
-    }
-  } catch (const std::exception& e) {
-    std::cerr << "Parquet read error: " << e.what() << std::endl;
-    return -1;
-  }
-
-  std::cout << "Parquet Writing and Reading Complete" << std::endl;
-
-  return 0;
-}
diff --git a/examples/low-level-api/reader_writer.h b/examples/low-level-api/reader_writer.h
deleted file mode 100644
index 3fda0cf..0000000
--- a/examples/low-level-api/reader_writer.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// 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.
-
-#include <arrow/io/file.h>
-#include <arrow/util/logging.h>
-
-#include <parquet/api/reader.h>
-#include <parquet/api/writer.h>
-
-using parquet::LogicalType;
-using parquet::Repetition;
-using parquet::Type;
-using parquet::schema::GroupNode;
-using parquet::schema::PrimitiveNode;
-
-constexpr int FIXED_LENGTH = 10;
-
-static std::shared_ptr<GroupNode> SetupSchema() {
-  parquet::schema::NodeVector fields;
-  // Create a primitive node named 'boolean_field' with type:BOOLEAN,
-  // repetition:REQUIRED
-  fields.push_back(PrimitiveNode::Make("boolean_field", Repetition::REQUIRED,
-                                       Type::BOOLEAN, LogicalType::NONE));
-
-  // Create a primitive node named 'int32_field' with type:INT32, repetition:REQUIRED,
-  // logical type:TIME_MILLIS
-  fields.push_back(PrimitiveNode::Make("int32_field", Repetition::REQUIRED, Type::INT32,
-                                       LogicalType::TIME_MILLIS));
-
-  // Create a primitive node named 'int64_field' with type:INT64, repetition:REPEATED
-  fields.push_back(PrimitiveNode::Make("int64_field", Repetition::REPEATED, Type::INT64,
-                                       LogicalType::NONE));
-
-  fields.push_back(PrimitiveNode::Make("int96_field", Repetition::REQUIRED, Type::INT96,
-                                       LogicalType::NONE));
-
-  fields.push_back(PrimitiveNode::Make("float_field", Repetition::REQUIRED, Type::FLOAT,
-                                       LogicalType::NONE));
-
-  fields.push_back(PrimitiveNode::Make("double_field", Repetition::REQUIRED, Type::DOUBLE,
-                                       LogicalType::NONE));
-
-  // Create a primitive node named 'ba_field' with type:BYTE_ARRAY, repetition:OPTIONAL
-  fields.push_back(PrimitiveNode::Make("ba_field", Repetition::OPTIONAL, Type::BYTE_ARRAY,
-                                       LogicalType::NONE));
-
-  // Create a primitive node named 'flba_field' with type:FIXED_LEN_BYTE_ARRAY,
-  // repetition:REQUIRED, field_length = FIXED_LENGTH
-  fields.push_back(PrimitiveNode::Make("flba_field", Repetition::REQUIRED,
-                                       Type::FIXED_LEN_BYTE_ARRAY, LogicalType::NONE,
-                                       FIXED_LENGTH));
-
-  // Create a GroupNode named 'schema' using the primitive nodes defined above
-  // This GroupNode is the root node of the schema tree
-  return std::static_pointer_cast<GroupNode>(
-      GroupNode::Make("schema", Repetition::REQUIRED, fields));
-}
diff --git a/examples/parquet-arrow/CMakeLists.txt b/examples/parquet-arrow/CMakeLists.txt
deleted file mode 100644
index 897fcfb..0000000
--- a/examples/parquet-arrow/CMakeLists.txt
+++ /dev/null
@@ -1,78 +0,0 @@
-# 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.
-
-# Require cmake that supports BYPRODUCTS in add_custom_command, ExternalProject_Add [1].
-cmake_minimum_required(VERSION 3.2.0)
-
-project(parquet-arrow-example)
-
-include(ExternalProject)
-include(FindPkgConfig)
-include(GNUInstallDirs)
-
-set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake_modules")
-
-# This ensures that things like gnu++11 get passed correctly
-set(CMAKE_CXX_STANDARD 11)
-
-# We require a C++11 compliant compiler
-set(CMAKE_CXX_STANDARD_REQUIRED ON)
-
-# We want to link dynamically against Arrow and Parquet
-set(PARQUET_BUILD_SHARED ON)
-
-
-# First search the packages in the system. If they are not found, use CMake's
-# ExternalProject mechanism to build them locally.
-find_package(Arrow)
-if (NOT ARROW_FOUND)
-  # set compile output directory
-  if (NOT CMAKE_BUILD_TYPE)
-    set(CMAKE_BUILD_TYPE Debug)
-  endif(NOT CMAKE_BUILD_TYPE)
-  string (TOLOWER ${CMAKE_BUILD_TYPE} BUILD_SUBDIR_NAME)
-  # If build in-source, create the latest symlink. If build out-of-source, which is
-  # preferred, simply output the binaries in the build folder
-  if (${CMAKE_SOURCE_DIR} STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
-    set(BUILD_OUTPUT_ROOT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/build/${BUILD_SUBDIR_NAME}")
-    # Link build/latest to the current build directory, to avoid developers
-    # accidentally running the latest debug build when in fact they're building
-    # release builds.
-    FILE(MAKE_DIRECTORY ${BUILD_OUTPUT_ROOT_DIRECTORY})
-    if (NOT APPLE)
-      set(MORE_ARGS "-T")
-    endif()
-  EXECUTE_PROCESS(COMMAND ln ${MORE_ARGS} -sf ${BUILD_OUTPUT_ROOT_DIRECTORY}
-    ${CMAKE_CURRENT_BINARY_DIR}/build/latest)
-  else()
-    set(BUILD_OUTPUT_ROOT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${BUILD_SUBDIR_NAME}")
-  endif()
-
-  include(ArrowExternalProject)
-  set(ARROW_VENDORED 1)
-else()
-  set(ARROW_VENDORED 0)
-endif()
-find_package(Parquet)
-
-include_directories(SYSTEM ${ARROW_INCLUDE_DIR} ${PARQUET_INCLUDE_DIR})
-
-add_executable(parquet-arrow-reader-writer src/reader-writer.cc)
-target_link_libraries(parquet-arrow-reader-writer ${PARQUET_SHARED_LIB} ${ARROW_SHARED_LIB})
-if (ARROW_VENDORED)
-  add_dependencies(parquet-arrow-reader-writer arrow_ep)
-endif()
diff --git a/examples/parquet-arrow/README.md b/examples/parquet-arrow/README.md
deleted file mode 100644
index e99819f..0000000
--- a/examples/parquet-arrow/README.md
+++ /dev/null
@@ -1,20 +0,0 @@
-<!---
-  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. See accompanying LICENSE file.
--->
-
-Using parquet-cpp with the arrow interface
-==========================================
-
-This folder contains an example project that shows how to setup a CMake project
-that consumes `parquet-cpp` as a library as well as how you can use the
-`parquet/arrow` interface to reading and write Apache Parquet files.
diff --git a/examples/parquet-arrow/cmake_modules/ArrowExternalProject.cmake b/examples/parquet-arrow/cmake_modules/ArrowExternalProject.cmake
deleted file mode 120000
index b535f6e..0000000
--- a/examples/parquet-arrow/cmake_modules/ArrowExternalProject.cmake
+++ /dev/null
@@ -1 +0,0 @@
-../../../cmake_modules/ArrowExternalProject.cmake
\ No newline at end of file
diff --git a/examples/parquet-arrow/cmake_modules/FindArrow.cmake b/examples/parquet-arrow/cmake_modules/FindArrow.cmake
deleted file mode 120000
index 6c451ce..0000000
--- a/examples/parquet-arrow/cmake_modules/FindArrow.cmake
+++ /dev/null
@@ -1 +0,0 @@
-../../../cmake_modules/FindArrow.cmake
\ No newline at end of file
diff --git a/examples/parquet-arrow/cmake_modules/FindParquet.cmake b/examples/parquet-arrow/cmake_modules/FindParquet.cmake
deleted file mode 100644
index 8bbe05f..0000000
--- a/examples/parquet-arrow/cmake_modules/FindParquet.cmake
+++ /dev/null
@@ -1,145 +0,0 @@
-# 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.
-
-# - Find PARQUET (parquet/parquet.h, libparquet.a, libparquet.so)
-# This module defines
-#  PARQUET_INCLUDE_DIR, directory containing headers
-#  PARQUET_LIBS, directory containing parquet libraries
-#  PARQUET_STATIC_LIB, path to libparquet.a
-#  PARQUET_SHARED_LIB, path to libparquet's shared library
-#  PARQUET_SHARED_IMP_LIB, path to libparquet's import library (MSVC only)
-#  PARQUET_FOUND, whether parquet has been found
-
-include(FindPkgConfig)
-
-if(NOT "$ENV{PARQUET_HOME}" STREQUAL "")
-    set(PARQUET_HOME "$ENV{PARQUET_HOME}")
-endif()
-
-if (MSVC)
-  SET(CMAKE_FIND_LIBRARY_SUFFIXES ".lib" ".dll")
-
-  if (MSVC AND NOT PARQUET_MSVC_STATIC_LIB_SUFFIX)
-    set(PARQUET_MSVC_STATIC_LIB_SUFFIX "_static")
-  endif()
-
-  find_library(PARQUET_SHARED_LIBRARIES NAMES parquet
-    PATHS ${PARQUET_HOME} NO_DEFAULT_PATH
-    PATH_SUFFIXES "bin" )
-
-  get_filename_component(PARQUET_SHARED_LIBS ${PARQUET_SHARED_LIBRARIES} PATH )
-endif ()
-
-if(PARQUET_HOME)
-    set(PARQUET_SEARCH_HEADER_PATHS
-        ${PARQUET_HOME}/include
-        )
-    set(PARQUET_SEARCH_LIB_PATH
-        ${PARQUET_HOME}/lib
-        )
-    find_path(PARQUET_INCLUDE_DIR parquet/api/reader.h PATHS
-        ${PARQUET_SEARCH_HEADER_PATHS}
-        # make sure we don't accidentally pick up a different version
-        NO_DEFAULT_PATH
-        )
-    find_library(PARQUET_LIBRARIES NAMES parquet
-        PATHS ${PARQUET_HOME} NO_DEFAULT_PATH
-        PATH_SUFFIXES "lib")
-    get_filename_component(PARQUET_LIBS ${PARQUET_LIBRARIES} PATH )
-
-    # Try to autodiscover the Parquet ABI version
-    get_filename_component(PARQUET_LIB_REALPATH ${PARQUET_LIBRARIES} REALPATH)
-    get_filename_component(PARQUET_EXT_REALPATH ${PARQUET_LIB_REALPATH} EXT)
-    string(REGEX MATCH ".([0-9]+.[0-9]+.[0-9]+)" HAS_ABI_VERSION ${PARQUET_EXT_REALPATH})
-    if (HAS_ABI_VERSION)
-      if (APPLE)
-        string(REGEX REPLACE ".([0-9]+.[0-9]+.[0-9]+).dylib" "\\1" PARQUET_ABI_VERSION ${PARQUET_EXT_REALPATH})
-      else()
-        string(REGEX REPLACE ".so.([0-9]+.[0-9]+.[0-9]+)" "\\1" PARQUET_ABI_VERSION ${PARQUET_EXT_REALPATH})
-      endif()
-      string(REGEX REPLACE "([0-9]+).[0-9]+.[0-9]+" "\\1" PARQUET_SO_VERSION ${PARQUET_ABI_VERSION})
-    else()
-      set(PARQUET_ABI_VERSION "1.0.0")
-      set(PARQUET_SO_VERSION "1")
-    endif()
-else()
-    pkg_check_modules(PARQUET parquet)
-    if (PARQUET_FOUND)
-        pkg_get_variable(PARQUET_ABI_VERSION parquet abi_version)
-        message(STATUS "Parquet C++ ABI version: ${PARQUET_ABI_VERSION}")
-        pkg_get_variable(PARQUET_SO_VERSION parquet so_version)
-        message(STATUS "Parquet C++ SO version: ${PARQUET_SO_VERSION}")
-        set(PARQUET_INCLUDE_DIR ${PARQUET_INCLUDE_DIRS})
-        set(PARQUET_LIBS ${PARQUET_LIBRARY_DIRS})
-        set(PARQUET_SEARCH_LIB_PATH ${PARQUET_LIBRARY_DIRS})
-        message(STATUS "Searching for parquet libs in: ${PARQUET_SEARCH_LIB_PATH}")
-        find_library(PARQUET_LIBRARIES NAMES parquet
-            PATHS ${PARQUET_SEARCH_LIB_PATH} NO_DEFAULT_PATH)
-    else()
-        find_path(PARQUET_INCLUDE_DIR NAMES parquet/api/reader.h )
-        find_library(PARQUET_LIBRARIES NAMES parquet)
-        get_filename_component(PARQUET_LIBS ${PARQUET_LIBRARIES} PATH )
-    endif()
-endif()
-
-if (PARQUET_INCLUDE_DIR AND PARQUET_LIBRARIES)
-  set(PARQUET_FOUND TRUE)
-  set(PARQUET_LIB_NAME parquet)
-  if (MSVC)
-    set(PARQUET_STATIC_LIB "${PARQUET_LIBS}/${PARQUET_LIB_NAME}${PARQUET_MSVC_STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}")
-    set(PARQUET_SHARED_LIB "${PARQUET_SHARED_LIBS}/${PARQUET_LIB_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX}")
-    set(PARQUET_SHARED_IMP_LIB "${PARQUET_LIBS}/${PARQUET_LIB_NAME}.lib")
-  else()
-    set(PARQUET_STATIC_LIB ${PARQUET_LIBS}/${CMAKE_STATIC_LIBRARY_PREFIX}${PARQUET_LIB_NAME}.a)
-    set(PARQUET_SHARED_LIB ${PARQUET_LIBS}/${CMAKE_SHARED_LIBRARY_PREFIX}${PARQUET_LIB_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX})
-  endif()
-else ()
-  set(PARQUET_FOUND FALSE)
-endif ()
-
-if (PARQUET_FOUND)
-  if (NOT Parquet_FIND_QUIETLY)
-    message(STATUS "Found the Parquet library: ${PARQUET_LIBRARIES}")
-  endif ()
-else ()
-  if (NOT Parquet_FIND_QUIETLY)
-    if (NOT PARQUET_FOUND)
-      set(PARQUET_ERR_MSG "${PARQUET_ERR_MSG} Could not find the parquet library.")
-    endif()
-
-    set(PARQUET_ERR_MSG "${PARQUET_ERR_MSG} Looked in ")
-    if ( _parquet_roots )
-      set(PARQUET_ERR_MSG "${PARQUET_ERR_MSG} in ${_parquet_roots}.")
-    else ()
-      set(PARQUET_ERR_MSG "${PARQUET_ERR_MSG} system search paths.")
-    endif ()
-    if (Parquet_FIND_REQUIRED)
-      message(FATAL_ERROR "${PARQUET_ERR_MSG}")
-    else (Parquet_FIND_REQUIRED)
-      message(STATUS "${PARQUET_ERR_MSG}")
-    endif (Parquet_FIND_REQUIRED)
-  endif ()
-endif ()
-
-mark_as_advanced(
-  PARQUET_FOUND
-  PARQUET_INCLUDE_DIR
-  PARQUET_LIBS
-  PARQUET_LIBRARIES
-  PARQUET_STATIC_LIB
-  PARQUET_SHARED_LIB
-)
diff --git a/examples/parquet-arrow/src/reader-writer.cc b/examples/parquet-arrow/src/reader-writer.cc
deleted file mode 100644
index f333cab..0000000
--- a/examples/parquet-arrow/src/reader-writer.cc
+++ /dev/null
@@ -1,134 +0,0 @@
-// 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.
-
-#include <arrow/api.h>
-#include <arrow/io/api.h>
-#include <parquet/arrow/reader.h>
-#include <parquet/arrow/writer.h>
-#include <parquet/exception.h>
-
-// #0 Build dummy data to pass around
-// To have some input data, we first create an Arrow Table that holds
-// some data.
-std::shared_ptr<arrow::Table> generate_table() {
-  arrow::Int64Builder i64builder;
-  PARQUET_THROW_NOT_OK(i64builder.Append({1, 2, 3, 4, 5}));
-  std::shared_ptr<arrow::Array> i64array;
-  PARQUET_THROW_NOT_OK(i64builder.Finish(&i64array));
-
-  arrow::StringBuilder strbuilder;
-  PARQUET_THROW_NOT_OK(strbuilder.Append("some"));
-  PARQUET_THROW_NOT_OK(strbuilder.Append("string"));
-  PARQUET_THROW_NOT_OK(strbuilder.Append("content"));
-  PARQUET_THROW_NOT_OK(strbuilder.Append("in"));
-  PARQUET_THROW_NOT_OK(strbuilder.Append("rows"));
-  std::shared_ptr<arrow::Array> strarray;
-  PARQUET_THROW_NOT_OK(strbuilder.Finish(&strarray));
-
-  std::shared_ptr<arrow::Schema> schema = arrow::schema(
-      {arrow::field("int", arrow::int64()), arrow::field("str", arrow::utf8())});
-
-  return arrow::Table::Make(schema, {i64array, strarray});
-}
-
-// #1 Write out the data as a Parquet file
-void write_parquet_file(const arrow::Table& table) {
-  std::shared_ptr<arrow::io::FileOutputStream> outfile;
-  PARQUET_THROW_NOT_OK(
-      arrow::io::FileOutputStream::Open("parquet-arrow-example.parquet", &outfile));
-  // The last argument to the function call is the size of the RowGroup in
-  // the parquet file. Normally you would choose this to be rather large but
-  // for the example, we use a small value to have multiple RowGroups.
-  PARQUET_THROW_NOT_OK(
-      parquet::arrow::WriteTable(table, arrow::default_memory_pool(), outfile, 3));
-}
-
-// #2: Fully read in the file
-void read_whole_file() {
-  std::cout << "Reading parquet-arrow-example.parquet at once" << std::endl;
-  std::shared_ptr<arrow::io::ReadableFile> infile;
-  PARQUET_THROW_NOT_OK(arrow::io::ReadableFile::Open(
-      "parquet-arrow-example.parquet", arrow::default_memory_pool(), &infile));
-
-  std::unique_ptr<parquet::arrow::FileReader> reader;
-  PARQUET_THROW_NOT_OK(
-      parquet::arrow::OpenFile(infile, arrow::default_memory_pool(), &reader));
-  std::shared_ptr<arrow::Table> table;
-  PARQUET_THROW_NOT_OK(reader->ReadTable(&table));
-  std::cout << "Loaded " << table->num_rows() << " rows in " << table->num_columns()
-            << " columns." << std::endl;
-}
-
-// #3: Read only a single RowGroup of the parquet file
-void read_single_rowgroup() {
-  std::cout << "Reading first RowGroup of parquet-arrow-example.parquet" << std::endl;
-  std::shared_ptr<arrow::io::ReadableFile> infile;
-  PARQUET_THROW_NOT_OK(arrow::io::ReadableFile::Open(
-      "parquet-arrow-example.parquet", arrow::default_memory_pool(), &infile));
-
-  std::unique_ptr<parquet::arrow::FileReader> reader;
-  PARQUET_THROW_NOT_OK(
-      parquet::arrow::OpenFile(infile, arrow::default_memory_pool(), &reader));
-  std::shared_ptr<arrow::Table> table;
-  PARQUET_THROW_NOT_OK(reader->RowGroup(0)->ReadTable(&table));
-  std::cout << "Loaded " << table->num_rows() << " rows in " << table->num_columns()
-            << " columns." << std::endl;
-}
-
-// #4: Read only a single column of the whole parquet file
-void read_single_column() {
-  std::cout << "Reading first column of parquet-arrow-example.parquet" << std::endl;
-  std::shared_ptr<arrow::io::ReadableFile> infile;
-  PARQUET_THROW_NOT_OK(arrow::io::ReadableFile::Open(
-      "parquet-arrow-example.parquet", arrow::default_memory_pool(), &infile));
-
-  std::unique_ptr<parquet::arrow::FileReader> reader;
-  PARQUET_THROW_NOT_OK(
-      parquet::arrow::OpenFile(infile, arrow::default_memory_pool(), &reader));
-  std::shared_ptr<arrow::Array> array;
-  PARQUET_THROW_NOT_OK(reader->ReadColumn(0, &array));
-  PARQUET_THROW_NOT_OK(arrow::PrettyPrint(*array, 4, &std::cout));
-  std::cout << std::endl;
-}
-
-// #5: Read only a single column of a RowGroup (this is known as ColumnChunk)
-//     from the Parquet file.
-void read_single_column_chunk() {
-  std::cout << "Reading first ColumnChunk of the first RowGroup of "
-               "parquet-arrow-example.parquet"
-            << std::endl;
-  std::shared_ptr<arrow::io::ReadableFile> infile;
-  PARQUET_THROW_NOT_OK(arrow::io::ReadableFile::Open(
-      "parquet-arrow-example.parquet", arrow::default_memory_pool(), &infile));
-
-  std::unique_ptr<parquet::arrow::FileReader> reader;
-  PARQUET_THROW_NOT_OK(
-      parquet::arrow::OpenFile(infile, arrow::default_memory_pool(), &reader));
-  std::shared_ptr<arrow::Array> array;
-  PARQUET_THROW_NOT_OK(reader->RowGroup(0)->Column(0)->Read(&array));
-  PARQUET_THROW_NOT_OK(arrow::PrettyPrint(*array, 4, &std::cout));
-  std::cout << std::endl;
-}
-
-int main(int argc, char** argv) {
-  std::shared_ptr<arrow::Table> table = generate_table();
-  write_parquet_file(*table);
-  read_whole_file();
-  read_single_rowgroup();
-  read_single_column();
-  read_single_column_chunk();
-}
diff --git a/src/parquet/.gitignore b/src/parquet/.gitignore
deleted file mode 100644
index 0695270..0000000
--- a/src/parquet/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-parquet_constants.*
-parquet_types.*
\ No newline at end of file
diff --git a/src/parquet/CMakeLists.txt b/src/parquet/CMakeLists.txt
deleted file mode 100644
index 93a242c..0000000
--- a/src/parquet/CMakeLists.txt
+++ /dev/null
@@ -1,72 +0,0 @@
-# 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.
-
-# Headers: top level
-install(FILES
-  bloom_filter.h
-  column_reader.h
-  column_page.h
-  column_scanner.h
-  column_writer.h
-  encoding.h
-  exception.h
-  file_reader.h
-  file_writer.h
-  hasher.h
-  metadata.h
-  murmur3.h
-  printer.h
-  properties.h
-  schema.h
-  statistics.h
-  types.h
-  DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/parquet")
-
-configure_file(parquet_version.h.in
-  "${CMAKE_CURRENT_SOURCE_DIR}/parquet_version.h"
-  @ONLY)
-
-install(FILES
-  "${CMAKE_CURRENT_SOURCE_DIR}/parquet_version.h"
-  DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/parquet")
-
-# pkg-config support
-configure_file(parquet.pc.in
-  "${CMAKE_CURRENT_BINARY_DIR}/parquet.pc"
-  @ONLY)
-
-install(FILES
-  "${CMAKE_CURRENT_BINARY_DIR}/parquet.pc"
-  DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig/")
-
-ADD_PARQUET_TEST(bloom_filter-test)
-ADD_PARQUET_TEST(column_reader-test)
-ADD_PARQUET_TEST(column_scanner-test)
-ADD_PARQUET_TEST(column_writer-test)
-ADD_PARQUET_TEST(file-deserialize-test)
-ADD_PARQUET_TEST(file-serialize-test)
-ADD_PARQUET_TEST(properties-test)
-ADD_PARQUET_TEST(statistics-test)
-ADD_PARQUET_TEST(encoding-test)
-ADD_PARQUET_TEST(metadata-test)
-ADD_PARQUET_TEST(public-api-test)
-ADD_PARQUET_TEST(types-test)
-ADD_PARQUET_TEST(reader-test)
-ADD_PARQUET_TEST(schema-test)
-
-ADD_PARQUET_BENCHMARK(column-io-benchmark)
-ADD_PARQUET_BENCHMARK(encoding-benchmark)
diff --git a/src/parquet/README b/src/parquet/README
deleted file mode 100644
index fc16a46..0000000
--- a/src/parquet/README
+++ /dev/null
@@ -1,10 +0,0 @@
-The CompatibilityTest of bloom_filter-test.cc is used to test cross compatibility of
-Bloom filters between parquet-mr and parquet-cpp. It reads the Bloom filter binary
-generated by the Bloom filter class in the parquet-mr project and tests whether the
-values inserted before could be filtered or not.
-
-The Bloom filter binary is generated by three steps from Parquet-mr:
-Step 1: Construct a Bloom filter with 1024 bytes of bitset.
-Step 2: Insert hashes of "hello", "parquet", "bloom", "filter" strings to Bloom filter
-by calling hash and insert APIs.
-Step 3: Call writeTo API to write to File.
diff --git a/src/parquet/api/CMakeLists.txt b/src/parquet/api/CMakeLists.txt
deleted file mode 100644
index 79fc716..0000000
--- a/src/parquet/api/CMakeLists.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-# 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.
-
-# Headers: public api
-install(FILES
-  io.h
-  reader.h
-  writer.h
-  schema.h
-  DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/parquet/api")
diff --git a/src/parquet/api/io.h b/src/parquet/api/io.h
deleted file mode 100644
index 96d3bc0..0000000
--- a/src/parquet/api/io.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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.
-
-#ifndef PARQUET_API_IO_H
-#define PARQUET_API_IO_H
-
-#include "parquet/exception.h"
-#include "parquet/util/memory.h"
-
-#endif  // PARQUET_API_IO_H
diff --git a/src/parquet/api/reader.h b/src/parquet/api/reader.h
deleted file mode 100644
index 505654f..0000000
--- a/src/parquet/api/reader.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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.
-
-#ifndef PARQUET_API_READER_H
-#define PARQUET_API_READER_H
-
-// Column reader API
-#include "parquet/column_reader.h"
-#include "parquet/column_scanner.h"
-#include "parquet/exception.h"
-#include "parquet/file_reader.h"
-#include "parquet/metadata.h"
-#include "parquet/printer.h"
-
-// Schemas
-#include "parquet/api/schema.h"
-
-// IO
-#include "parquet/api/io.h"
-
-#endif  // PARQUET_API_READER_H
diff --git a/src/parquet/api/schema.h b/src/parquet/api/schema.h
deleted file mode 100644
index 2e6c3b3..0000000
--- a/src/parquet/api/schema.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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.
-
-#ifndef PARQUET_API_SCHEMA_H
-#define PARQUET_API_SCHEMA_H
-
-// Schemas
-#include "parquet/schema.h"
-
-#endif  // PARQUET_API_SCHEMA_H
diff --git a/src/parquet/api/writer.h b/src/parquet/api/writer.h
deleted file mode 100644
index 3b4e42f..0000000
--- a/src/parquet/api/writer.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// 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.
-
-#ifndef PARQUET_API_WRITER_H
-#define PARQUET_API_WRITER_H
-
-#include "parquet/api/io.h"
-#include "parquet/api/schema.h"
-#include "parquet/column_writer.h"
-#include "parquet/exception.h"
-#include "parquet/file_writer.h"
-
-#endif  // PARQUET_API_WRITER_H
diff --git a/src/parquet/arrow/CMakeLists.txt b/src/parquet/arrow/CMakeLists.txt
deleted file mode 100644
index 616555f..0000000
--- a/src/parquet/arrow/CMakeLists.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-# 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.
-
-ADD_PARQUET_TEST(arrow-schema-test)
-ADD_PARQUET_TEST(arrow-reader-writer-test)
-
-if(PARQUET_BUILD_BENCHMARKS)
-  ADD_PARQUET_BENCHMARK(arrow-reader-writer-benchmark)
-endif()
-
-# Headers: top level
-install(FILES
-  reader.h
-  schema.h
-  writer.h
-  DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/parquet/arrow")
diff --git a/src/parquet/arrow/arrow-reader-writer-benchmark.cc b/src/parquet/arrow/arrow-reader-writer-benchmark.cc
deleted file mode 100644
index 41cb88d..0000000
--- a/src/parquet/arrow/arrow-reader-writer-benchmark.cc
+++ /dev/null
@@ -1,263 +0,0 @@
-// 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.
-
-#include "benchmark/benchmark.h"
-
-#include <iostream>
-
-#include "parquet/arrow/reader.h"
-#include "parquet/arrow/writer.h"
-#include "parquet/column_reader.h"
-#include "parquet/column_writer.h"
-#include "parquet/file_reader.h"
-#include "parquet/file_writer.h"
-#include "parquet/util/memory.h"
-
-#include "arrow/api.h"
-
-using arrow::BooleanBuilder;
-using arrow::NumericBuilder;
-
-#define EXIT_NOT_OK(s)                                        \
-  do {                                                        \
-    ::arrow::Status _s = (s);                                 \
-    if (ARROW_PREDICT_FALSE(!_s.ok())) {                      \
-      std::cout << "Exiting: " << _s.ToString() << std::endl; \
-      exit(EXIT_FAILURE);                                     \
-    }                                                         \
-  } while (0)
-
-namespace parquet {
-
-using arrow::FileReader;
-using arrow::WriteTable;
-using schema::PrimitiveNode;
-
-namespace benchmark {
-
-// This should result in multiple pages for most primitive types
-constexpr int64_t BENCHMARK_SIZE = 10 * 1024 * 1024;
-
-template <typename ParquetType>
-struct benchmark_traits {};
-
-template <>
-struct benchmark_traits<Int32Type> {
-  using arrow_type = ::arrow::Int32Type;
-};
-
-template <>
-struct benchmark_traits<Int64Type> {
-  using arrow_type = ::arrow::Int64Type;
-};
-
-template <>
-struct benchmark_traits<DoubleType> {
-  using arrow_type = ::arrow::DoubleType;
-};
-
-template <>
-struct benchmark_traits<BooleanType> {
-  using arrow_type = ::arrow::BooleanType;
-};
-
-template <typename ParquetType>
-using ArrowType = typename benchmark_traits<ParquetType>::arrow_type;
-
-template <typename ParquetType>
-std::shared_ptr<ColumnDescriptor> MakeSchema(Repetition::type repetition) {
-  auto node = PrimitiveNode::Make("int64", repetition, ParquetType::type_num);
-  return std::make_shared<ColumnDescriptor>(node, repetition != Repetition::REQUIRED,
-                                            repetition == Repetition::REPEATED);
-}
-
-template <bool nullable, typename ParquetType>
-void SetBytesProcessed(::benchmark::State& state) {
-  int64_t bytes_processed =
-      state.iterations() * BENCHMARK_SIZE * sizeof(typename ParquetType::c_type);
-  if (nullable) {
-    bytes_processed += state.iterations() * BENCHMARK_SIZE * sizeof(int16_t);
-  }
-  state.SetBytesProcessed(bytes_processed);
-}
-
-template <typename ParquetType>
-std::shared_ptr<::arrow::Table> TableFromVector(
-    const std::vector<typename ParquetType::c_type>& vec, bool nullable) {
-  ::arrow::TypePtr type = std::make_shared<ArrowType<ParquetType>>();
-  NumericBuilder<ArrowType<ParquetType>> builder;
-  if (nullable) {
-    std::vector<uint8_t> valid_bytes(BENCHMARK_SIZE, 0);
-    int n = {0};
-    std::generate(valid_bytes.begin(), valid_bytes.end(), [&n] { return n++ % 2; });
-    EXIT_NOT_OK(builder.AppendValues(vec.data(), vec.size(), valid_bytes.data()));
-  } else {
-    EXIT_NOT_OK(builder.AppendValues(vec.data(), vec.size(), nullptr));
-  }
-  std::shared_ptr<::arrow::Array> array;
-  EXIT_NOT_OK(builder.Finish(&array));
-
-  auto field = ::arrow::field("column", type, nullable);
-  auto schema = ::arrow::schema({field});
-  auto column = std::make_shared<::arrow::Column>(field, array);
-  return ::arrow::Table::Make(schema, {column});
-}
-
-template <>
-std::shared_ptr<::arrow::Table> TableFromVector<BooleanType>(const std::vector<bool>& vec,
-                                                             bool nullable) {
-  BooleanBuilder builder;
-  if (nullable) {
-    std::vector<bool> valid_bytes(BENCHMARK_SIZE, 0);
-    int n = {0};
-    std::generate(valid_bytes.begin(), valid_bytes.end(),
-                  [&n] { return (n++ % 2) != 0; });
-    EXIT_NOT_OK(builder.AppendValues(vec, valid_bytes));
-  } else {
-    EXIT_NOT_OK(builder.AppendValues(vec));
-  }
-  std::shared_ptr<::arrow::Array> array;
-  EXIT_NOT_OK(builder.Finish(&array));
-
-  auto field = ::arrow::field("column", ::arrow::boolean(), nullable);
-  auto schema = std::make_shared<::arrow::Schema>(
-      std::vector<std::shared_ptr<::arrow::Field>>({field}));
-  auto column = std::make_shared<::arrow::Column>(field, array);
-  return ::arrow::Table::Make(schema, {column});
-}
-
-template <bool nullable, typename ParquetType>
-static void BM_WriteColumn(::benchmark::State& state) {
-  std::vector<typename ParquetType::c_type> values(BENCHMARK_SIZE, 128);
-  std::shared_ptr<::arrow::Table> table = TableFromVector<ParquetType>(values, nullable);
-
-  while (state.KeepRunning()) {
-    auto output = std::make_shared<InMemoryOutputStream>();
-    EXIT_NOT_OK(
-        WriteTable(*table, ::arrow::default_memory_pool(), output, BENCHMARK_SIZE));
-  }
-  SetBytesProcessed<nullable, ParquetType>(state);
-}
-
-BENCHMARK_TEMPLATE2(BM_WriteColumn, false, Int32Type);
-BENCHMARK_TEMPLATE2(BM_WriteColumn, true, Int32Type);
-
-BENCHMARK_TEMPLATE2(BM_WriteColumn, false, Int64Type);
-BENCHMARK_TEMPLATE2(BM_WriteColumn, true, Int64Type);
-
-BENCHMARK_TEMPLATE2(BM_WriteColumn, false, DoubleType);
-BENCHMARK_TEMPLATE2(BM_WriteColumn, true, DoubleType);
-
-BENCHMARK_TEMPLATE2(BM_WriteColumn, false, BooleanType);
-BENCHMARK_TEMPLATE2(BM_WriteColumn, true, BooleanType);
-
-template <bool nullable, typename ParquetType>
-static void BM_ReadColumn(::benchmark::State& state) {
-  std::vector<typename ParquetType::c_type> values(BENCHMARK_SIZE, 128);
-  std::shared_ptr<::arrow::Table> table = TableFromVector<ParquetType>(values, nullable);
-  auto output = std::make_shared<InMemoryOutputStream>();
-  EXIT_NOT_OK(WriteTable(*table, ::arrow::default_memory_pool(), output, BENCHMARK_SIZE));
-  std::shared_ptr<Buffer> buffer = output->GetBuffer();
-
-  while (state.KeepRunning()) {
-    auto reader =
-        ParquetFileReader::Open(std::make_shared<::arrow::io::BufferReader>(buffer));
-    FileReader filereader(::arrow::default_memory_pool(), std::move(reader));
-    std::shared_ptr<::arrow::Table> table;
-    EXIT_NOT_OK(filereader.ReadTable(&table));
-  }
-  SetBytesProcessed<nullable, ParquetType>(state);
-}
-
-BENCHMARK_TEMPLATE2(BM_ReadColumn, false, Int32Type);
-BENCHMARK_TEMPLATE2(BM_ReadColumn, true, Int32Type);
-
-BENCHMARK_TEMPLATE2(BM_ReadColumn, false, Int64Type);
-BENCHMARK_TEMPLATE2(BM_ReadColumn, true, Int64Type);
-
-BENCHMARK_TEMPLATE2(BM_ReadColumn, false, DoubleType);
-BENCHMARK_TEMPLATE2(BM_ReadColumn, true, DoubleType);
-
-BENCHMARK_TEMPLATE2(BM_ReadColumn, false, BooleanType);
-BENCHMARK_TEMPLATE2(BM_ReadColumn, true, BooleanType);
-
-static void BM_ReadIndividualRowGroups(::benchmark::State& state) {
-  std::vector<int64_t> values(BENCHMARK_SIZE, 128);
-  std::shared_ptr<::arrow::Table> table = TableFromVector<Int64Type>(values, true);
-  auto output = std::make_shared<InMemoryOutputStream>();
-  // This writes 10 RowGroups
-  EXIT_NOT_OK(
-      WriteTable(*table, ::arrow::default_memory_pool(), output, BENCHMARK_SIZE / 10));
-  std::shared_ptr<Buffer> buffer = output->GetBuffer();
-
-  while (state.KeepRunning()) {
-    auto reader =
-        ParquetFileReader::Open(std::make_shared<::arrow::io::BufferReader>(buffer));
-    FileReader filereader(::arrow::default_memory_pool(), std::move(reader));
-
-    std::vector<std::shared_ptr<::arrow::Table>> tables;
-    for (int i = 0; i < filereader.num_row_groups(); i++) {
-      // Only read the even numbered RowGroups
-      if ((i % 2) == 0) {
-        std::shared_ptr<::arrow::Table> table;
-        EXIT_NOT_OK(filereader.RowGroup(i)->ReadTable(&table));
-        tables.push_back(table);
-      }
-    }
-
-    std::shared_ptr<::arrow::Table> final_table;
-    EXIT_NOT_OK(ConcatenateTables(tables, &final_table));
-  }
-  SetBytesProcessed<true, Int64Type>(state);
-}
-
-BENCHMARK(BM_ReadIndividualRowGroups);
-
-static void BM_ReadMultipleRowGroups(::benchmark::State& state) {
-  std::vector<int64_t> values(BENCHMARK_SIZE, 128);
-  std::shared_ptr<::arrow::Table> table = TableFromVector<Int64Type>(values, true);
-  auto output = std::make_shared<InMemoryOutputStream>();
-  // This writes 10 RowGroups
-  EXIT_NOT_OK(
-      WriteTable(*table, ::arrow::default_memory_pool(), output, BENCHMARK_SIZE / 10));
-  std::shared_ptr<Buffer> buffer = output->GetBuffer();
-
-  while (state.KeepRunning()) {
-    auto reader =
-        ParquetFileReader::Open(std::make_shared<::arrow::io::BufferReader>(buffer));
-    FileReader filereader(::arrow::default_memory_pool(), std::move(reader));
-
-    std::vector<std::shared_ptr<::arrow::Table>> tables;
-    std::vector<int> rgs;
-    for (int i = 0; i < filereader.num_row_groups(); i++) {
-      // Only read the even numbered RowGroups
-      if ((i % 2) == 0) {
-        rgs.push_back(i);
-      }
-    }
-
-    std::shared_ptr<::arrow::Table> table;
-    EXIT_NOT_OK(filereader.ReadRowGroups(rgs, &table));
-  }
-  SetBytesProcessed<true, Int64Type>(state);
-}
-
-BENCHMARK(BM_ReadMultipleRowGroups);
-
-}  // namespace benchmark
-
-}  // namespace parquet
diff --git a/src/parquet/arrow/arrow-reader-writer-test.cc b/src/parquet/arrow/arrow-reader-writer-test.cc
deleted file mode 100644
index 5f4e123..0000000
--- a/src/parquet/arrow/arrow-reader-writer-test.cc
+++ /dev/null
@@ -1,2376 +0,0 @@
-// 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.
-
-#ifdef _MSC_VER
-#pragma warning(push)
-// Disable forcing value to bool warnings
-#pragma warning(disable : 4800)
-#endif
-
-#include "gtest/gtest.h"
-
-#include <arrow/compute/api.h>
-#include <cstdint>
-#include <functional>
-#include <sstream>
-#include <vector>
-
-#include "parquet/api/reader.h"
-#include "parquet/api/writer.h"
-
-#include "parquet/arrow/reader.h"
-#include "parquet/arrow/schema.h"
-#include "parquet/arrow/test-util.h"
-#include "parquet/arrow/writer.h"
-
-#include "parquet/file_writer.h"
-
-#include "parquet/util/test-common.h"
-
-#include "arrow/api.h"
-#include "arrow/test-util.h"
-#include "arrow/type_traits.h"
-#include "arrow/util/decimal.h"
-
-using arrow::Array;
-using arrow::ArrayVisitor;
-using arrow::Buffer;
-using arrow::ChunkedArray;
-using arrow::Column;
-using arrow::DataType;
-using arrow::default_memory_pool;
-using arrow::ListArray;
-using arrow::PrimitiveArray;
-using arrow::ResizableBuffer;
-using arrow::Status;
-using arrow::Table;
-using arrow::TimeUnit;
-using arrow::compute::Datum;
-using arrow::compute::DictionaryEncode;
-using arrow::compute::FunctionContext;
-using arrow::io::BufferReader;
-
-using arrow::randint;
-using arrow::random_is_valid;
-
-using ArrowId = ::arrow::Type;
-using ParquetType = parquet::Type;
-using parquet::arrow::FromParquetSchema;
-using parquet::schema::GroupNode;
-using parquet::schema::NodePtr;
-using parquet::schema::PrimitiveNode;
-
-using ColumnVector = std::vector<std::shared_ptr<arrow::Column>>;
-
-namespace parquet {
-namespace arrow {
-
-static constexpr int SMALL_SIZE = 100;
-#ifdef PARQUET_VALGRIND
-static constexpr int LARGE_SIZE = 1000;
-#else
-static constexpr int LARGE_SIZE = 10000;
-#endif
-
-static constexpr uint32_t kDefaultSeed = 0;
-
-LogicalType::type get_logical_type(const ::DataType& type) {
-  switch (type.id()) {
-    case ArrowId::UINT8:
-      return LogicalType::UINT_8;
-    case ArrowId::INT8:
-      return LogicalType::INT_8;
-    case ArrowId::UINT16:
-      return LogicalType::UINT_16;
-    case ArrowId::INT16:
-      return LogicalType::INT_16;
-    case ArrowId::UINT32:
-      return LogicalType::UINT_32;
-    case ArrowId::INT32:
-      return LogicalType::INT_32;
-    case ArrowId::UINT64:
-      return LogicalType::UINT_64;
-    case ArrowId::INT64:
-      return LogicalType::INT_64;
-    case ArrowId::STRING:
-      return LogicalType::UTF8;
-    case ArrowId::DATE32:
-      return LogicalType::DATE;
-    case ArrowId::DATE64:
-      return LogicalType::DATE;
-    case ArrowId::TIMESTAMP: {
-      const auto& ts_type = static_cast<const ::arrow::TimestampType&>(type);
-      switch (ts_type.unit()) {
-        case TimeUnit::MILLI:
-          return LogicalType::TIMESTAMP_MILLIS;
-        case TimeUnit::MICRO:
-          return LogicalType::TIMESTAMP_MICROS;
-        default:
-          DCHECK(false) << "Only MILLI and MICRO units supported for Arrow timestamps "
-                           "with Parquet.";
-      }
-    }
-    case ArrowId::TIME32:
-      return LogicalType::TIME_MILLIS;
-    case ArrowId::TIME64:
-      return LogicalType::TIME_MICROS;
-    case ArrowId::DICTIONARY: {
-      const ::arrow::DictionaryType& dict_type =
-          static_cast<const ::arrow::DictionaryType&>(type);
-      return get_logical_type(*dict_type.dictionary()->type());
-    }
-    case ArrowId::DECIMAL:
-      return LogicalType::DECIMAL;
-    default:
-      break;
-  }
-  return LogicalType::NONE;
-}
-
-ParquetType::type get_physical_type(const ::DataType& type) {
-  switch (type.id()) {
-    case ArrowId::BOOL:
-      return ParquetType::BOOLEAN;
-    case ArrowId::UINT8:
-    case ArrowId::INT8:
-    case ArrowId::UINT16:
-    case ArrowId::INT16:
-    case ArrowId::UINT32:
-    case ArrowId::INT32:
-      return ParquetType::INT32;
-    case ArrowId::UINT64:
-    case ArrowId::INT64:
-      return ParquetType::INT64;
-    case ArrowId::FLOAT:
-      return ParquetType::FLOAT;
-    case ArrowId::DOUBLE:
-      return ParquetType::DOUBLE;
-    case ArrowId::BINARY:
-      return ParquetType::BYTE_ARRAY;
-    case ArrowId::STRING:
-      return ParquetType::BYTE_ARRAY;
-    case ArrowId::FIXED_SIZE_BINARY:
-    case ArrowId::DECIMAL:
-      return ParquetType::FIXED_LEN_BYTE_ARRAY;
-    case ArrowId::DATE32:
-      return ParquetType::INT32;
-    case ArrowId::DATE64:
-      // Convert to date32 internally
-      return ParquetType::INT32;
-    case ArrowId::TIME32:
-      return ParquetType::INT32;
-    case ArrowId::TIME64:
-      return ParquetType::INT64;
-    case ArrowId::TIMESTAMP:
-      return ParquetType::INT64;
-    case ArrowId::DICTIONARY: {
-      const ::arrow::DictionaryType& dict_type =
-          static_cast<const ::arrow::DictionaryType&>(type);
-      return get_physical_type(*dict_type.dictionary()->type());
-    }
-    default:
-      break;
-  }
-  DCHECK(false) << "cannot reach this code";
-  return ParquetType::INT32;
-}
-
-template <typename TestType>
-struct test_traits {};
-
-template <>
-struct test_traits<::arrow::BooleanType> {
-  static constexpr ParquetType::type parquet_enum = ParquetType::BOOLEAN;
-  static uint8_t const value;
-};
-
-const uint8_t test_traits<::arrow::BooleanType>::value(1);
-
-template <>
-struct test_traits<::arrow::UInt8Type> {
-  static constexpr ParquetType::type parquet_enum = ParquetType::INT32;
-  static uint8_t const value;
-};
-
-const uint8_t test_traits<::arrow::UInt8Type>::value(64);
-
-template <>
-struct test_traits<::arrow::Int8Type> {
-  static constexpr ParquetType::type parquet_enum = ParquetType::INT32;
-  static int8_t const value;
-};
-
-const int8_t test_traits<::arrow::Int8Type>::value(-64);
-
-template <>
-struct test_traits<::arrow::UInt16Type> {
-  static constexpr ParquetType::type parquet_enum = ParquetType::INT32;
-  static uint16_t const value;
-};
-
-const uint16_t test_traits<::arrow::UInt16Type>::value(1024);
-
-template <>
-struct test_traits<::arrow::Int16Type> {
-  static constexpr ParquetType::type parquet_enum = ParquetType::INT32;
-  static int16_t const value;
-};
-
-const int16_t test_traits<::arrow::Int16Type>::value(-1024);
-
-template <>
-struct test_traits<::arrow::UInt32Type> {
-  static constexpr ParquetType::type parquet_enum = ParquetType::INT32;
-  static uint32_t const value;
-};
-
-const uint32_t test_traits<::arrow::UInt32Type>::value(1024);
-
-template <>
-struct test_traits<::arrow::Int32Type> {
-  static constexpr ParquetType::type parquet_enum = ParquetType::INT32;
-  static int32_t const value;
-};
-
-const int32_t test_traits<::arrow::Int32Type>::value(-1024);
-
-template <>
-struct test_traits<::arrow::UInt64Type> {
-  static constexpr ParquetType::type parquet_enum = ParquetType::INT64;
-  static uint64_t const value;
-};
-
-const uint64_t test_traits<::arrow::UInt64Type>::value(1024);
-
-template <>
-struct test_traits<::arrow::Int64Type> {
-  static constexpr ParquetType::type parquet_enum = ParquetType::INT64;
-  static int64_t const value;
-};
-
-const int64_t test_traits<::arrow::Int64Type>::value(-1024);
-
-template <>
-struct test_traits<::arrow::TimestampType> {
-  static constexpr ParquetType::type parquet_enum = ParquetType::INT64;
-  static int64_t const value;
-};
-
-const int64_t test_traits<::arrow::TimestampType>::value(14695634030000);
-
-template <>
-struct test_traits<::arrow::Date32Type> {
-  static constexpr ParquetType::type parquet_enum = ParquetType::INT32;
-  static int32_t const value;
-};
-
-const int32_t test_traits<::arrow::Date32Type>::value(170000);
-
-template <>
-struct test_traits<::arrow::FloatType> {
-  static constexpr ParquetType::type parquet_enum = ParquetType::FLOAT;
-  static float const value;
-};
-
-const float test_traits<::arrow::FloatType>::value(2.1f);
-
-template <>
-struct test_traits<::arrow::DoubleType> {
-  static constexpr ParquetType::type parquet_enum = ParquetType::DOUBLE;
-  static double const value;
-};
-
-const double test_traits<::arrow::DoubleType>::value(4.2);
-
-template <>
-struct test_traits<::arrow::StringType> {
-  static constexpr ParquetType::type parquet_enum = ParquetType::BYTE_ARRAY;
-  static std::string const value;
-};
-
-template <>
-struct test_traits<::arrow::BinaryType> {
-  static constexpr ParquetType::type parquet_enum = ParquetType::BYTE_ARRAY;
-  static std::string const value;
-};
-
-template <>
-struct test_traits<::arrow::FixedSizeBinaryType> {
-  static constexpr ParquetType::type parquet_enum = ParquetType::FIXED_LEN_BYTE_ARRAY;
-  static std::string const value;
-};
-
-const std::string test_traits<::arrow::StringType>::value("Test");              // NOLINT
-const std::string test_traits<::arrow::BinaryType>::value("\x00\x01\x02\x03");  // NOLINT
-const std::string test_traits<::arrow::FixedSizeBinaryType>::value("Fixed");    // NOLINT
-
-template <typename T>
-using ParquetDataType = DataType<test_traits<T>::parquet_enum>;
-
-template <typename T>
-using ParquetWriter = TypedColumnWriter<ParquetDataType<T>>;
-
-void WriteTableToBuffer(const std::shared_ptr<Table>& table, int64_t row_group_size,
-                        const std::shared_ptr<ArrowWriterProperties>& arrow_properties,
-                        std::shared_ptr<Buffer>* out) {
-  auto sink = std::make_shared<InMemoryOutputStream>();
-
-  ASSERT_OK_NO_THROW(WriteTable(*table, ::arrow::default_memory_pool(), sink,
-                                row_group_size, default_writer_properties(),
-                                arrow_properties));
-  *out = sink->GetBuffer();
-}
-
-namespace internal {
-
-void AssertArraysEqual(const Array& expected, const Array& actual) {
-  if (!actual.Equals(expected)) {
-    std::stringstream pp_result;
-    std::stringstream pp_expected;
-
-    EXPECT_OK(::arrow::PrettyPrint(actual, 0, &pp_result));
-    EXPECT_OK(::arrow::PrettyPrint(expected, 0, &pp_expected));
-    FAIL() << "Got: \n" << pp_result.str() << "\nExpected: \n" << pp_expected.str();
-  }
-}
-
-}  // namespace internal
-
-void AssertChunkedEqual(const ChunkedArray& expected, const ChunkedArray& actual) {
-  ASSERT_EQ(expected.num_chunks(), actual.num_chunks()) << "# chunks unequal";
-  if (!actual.Equals(expected)) {
-    std::stringstream pp_result;
-    std::stringstream pp_expected;
-
-    for (int i = 0; i < actual.num_chunks(); ++i) {
-      auto c1 = actual.chunk(i);
-      auto c2 = expected.chunk(i);
-      if (!c1->Equals(*c2)) {
-        EXPECT_OK(::arrow::PrettyPrint(*c1, 0, &pp_result));
-        EXPECT_OK(::arrow::PrettyPrint(*c2, 0, &pp_expected));
-        FAIL() << "Chunk " << i << " Got: " << pp_result.str()
-               << "\nExpected: " << pp_expected.str();
-      }
-    }
-  }
-}
-
-void PrintColumn(const Column& col, std::stringstream* ss) {
-  const ChunkedArray& carr = *col.data();
-  for (int i = 0; i < carr.num_chunks(); ++i) {
-    auto c1 = carr.chunk(i);
-    *ss << "Chunk " << i << std::endl;
-    EXPECT_OK(::arrow::PrettyPrint(*c1, 0, ss));
-    *ss << std::endl;
-  }
-}
-
-void DoSimpleRoundtrip(const std::shared_ptr<Table>& table, bool use_threads,
-                       int64_t row_group_size, const std::vector<int>& column_subset,
-                       std::shared_ptr<Table>* out,
-                       const std::shared_ptr<ArrowWriterProperties>& arrow_properties =
-                           default_arrow_writer_properties()) {
-  std::shared_ptr<Buffer> buffer;
-  ASSERT_NO_FATAL_FAILURE(
-      WriteTableToBuffer(table, row_group_size, arrow_properties, &buffer));
-
-  std::unique_ptr<FileReader> reader;
-  ASSERT_OK_NO_THROW(OpenFile(std::make_shared<BufferReader>(buffer),
-                              ::arrow::default_memory_pool(),
-                              ::parquet::default_reader_properties(), nullptr, &reader));
-
-  reader->set_use_threads(use_threads);
-
-  if (column_subset.size() > 0) {
-    ASSERT_OK_NO_THROW(reader->ReadTable(column_subset, out));
-  } else {
-    // Read everything
-    ASSERT_OK_NO_THROW(reader->ReadTable(out));
-  }
-}
-
-void CheckSimpleRoundtrip(const std::shared_ptr<Table>& table, int64_t row_group_size,
-                          const std::shared_ptr<ArrowWriterProperties>& arrow_properties =
-                              default_arrow_writer_properties()) {
-  std::shared_ptr<Table> result;
-  DoSimpleRoundtrip(table, false /* use_threads */, row_group_size, {}, &result,
-                    arrow_properties);
-  ASSERT_NO_FATAL_FAILURE(::arrow::AssertTablesEqual(*table, *result, false));
-}
-
-static std::shared_ptr<GroupNode> MakeSimpleSchema(const ::DataType& type,
-                                                   Repetition::type repetition) {
-  int32_t byte_width = -1;
-  int32_t precision = -1;
-  int32_t scale = -1;
-
-  switch (type.id()) {
-    case ::arrow::Type::DICTIONARY: {
-      const auto& dict_type = static_cast<const ::arrow::DictionaryType&>(type);
-      const ::DataType& values_type = *dict_type.dictionary()->type();
-      switch (values_type.id()) {
-        case ::arrow::Type::FIXED_SIZE_BINARY:
-          byte_width =
-              static_cast<const ::arrow::FixedSizeBinaryType&>(values_type).byte_width();
-          break;
-        case ::arrow::Type::DECIMAL: {
-          const auto& decimal_type =
-              static_cast<const ::arrow::Decimal128Type&>(values_type);
-          precision = decimal_type.precision();
-          scale = decimal_type.scale();
-          byte_width = DecimalSize(precision);
-        } break;
-        default:
-          break;
-      }
-    } break;
-    case ::arrow::Type::FIXED_SIZE_BINARY:
-      byte_width = static_cast<const ::arrow::FixedSizeBinaryType&>(type).byte_width();
-      break;
-    case ::arrow::Type::DECIMAL: {
-      const auto& decimal_type = static_cast<const ::arrow::Decimal128Type&>(type);
-      precision = decimal_type.precision();
-      scale = decimal_type.scale();
-      byte_width = DecimalSize(precision);
-    } break;
-    default:
-      break;
-  }
-  auto pnode = PrimitiveNode::Make("column1", repetition, get_physical_type(type),
-                                   get_logical_type(type), byte_width, precision, scale);
-  NodePtr node_ =
-      GroupNode::Make("schema", Repetition::REQUIRED, std::vector<NodePtr>({pnode}));
-  return std::static_pointer_cast<GroupNode>(node_);
-}
-
-template <typename TestType>
-class TestParquetIO : public ::testing::Test {
- public:
-  virtual void SetUp() {}
-
-  std::unique_ptr<ParquetFileWriter> MakeWriter(
-      const std::shared_ptr<GroupNode>& schema) {
-    sink_ = std::make_shared<InMemoryOutputStream>();
-    return ParquetFileWriter::Open(sink_, schema);
-  }
-
-  void ReaderFromSink(std::unique_ptr<FileReader>* out) {
-    std::shared_ptr<Buffer> buffer = sink_->GetBuffer();
-    ASSERT_OK_NO_THROW(OpenFile(std::make_shared<BufferReader>(buffer),
-                                ::arrow::default_memory_pool(),
-                                ::parquet::default_reader_properties(), nullptr, out));
-  }
-
-  void ReadSingleColumnFile(std::unique_ptr<FileReader> file_reader,
-                            std::shared_ptr<Array>* out) {
-    std::unique_ptr<ColumnReader> column_reader;
-    ASSERT_OK_NO_THROW(file_reader->GetColumn(0, &column_reader));
-    ASSERT_NE(nullptr, column_reader.get());
-
-    ASSERT_OK(column_reader->NextBatch(SMALL_SIZE, out));
-    ASSERT_NE(nullptr, out->get());
-  }
-
-  void ReadAndCheckSingleColumnFile(const Array& values) {
-    std::shared_ptr<Array> out;
-
-    std::unique_ptr<FileReader> reader;
-    ReaderFromSink(&reader);
-    ReadSingleColumnFile(std::move(reader), &out);
-
-    internal::AssertArraysEqual(values, *out);
-  }
-
-  void ReadTableFromFile(std::unique_ptr<FileReader> reader,
-                         std::shared_ptr<Table>* out) {
-    ASSERT_OK_NO_THROW(reader->ReadTable(out));
-    auto key_value_metadata =
-        reader->parquet_reader()->metadata()->key_value_metadata().get();
-    ASSERT_EQ(nullptr, key_value_metadata);
-    ASSERT_NE(nullptr, out->get());
-  }
-
-  void PrepareListTable(int64_t size, bool nullable_lists, bool nullable_elements,
-                        int64_t null_count, std::shared_ptr<Table>* out) {
-    std::shared_ptr<Array> values;
-    ASSERT_OK(NullableArray<TestType>(size * size, nullable_elements ? null_count : 0,
-                                      kDefaultSeed, &values));
-    // Also test that slice offsets are respected
-    values = values->Slice(5, values->length() - 5);
-    std::shared_ptr<ListArray> lists;
-    ASSERT_OK(MakeListArray(values, size, nullable_lists ? null_count : 0,
-                            nullable_elements, &lists));
-    *out = MakeSimpleTable(lists->Slice(3, size - 6), nullable_lists);
-  }
-
-  // Prepare table of empty lists, with null values array (ARROW-2744)
-  void PrepareEmptyListsTable(int64_t size, std::shared_ptr<Table>* out) {
-    std::shared_ptr<Array> lists;
-    ASSERT_OK(MakeEmptyListsArray(size, &lists));
-    *out = MakeSimpleTable(lists, true /* nullable_lists */);
-  }
-
-  void PrepareListOfListTable(int64_t size, bool nullable_parent_lists,
-                              bool nullable_lists, bool nullable_elements,
-                              int64_t null_count, std::shared_ptr<Table>* out) {
-    std::shared_ptr<Array> values;
-    ASSERT_OK(NullableArray<TestType>(size * 6, nullable_elements ? null_count : 0,
-                                      kDefaultSeed, &values));
-    std::shared_ptr<ListArray> lists;
-    ASSERT_OK(MakeListArray(values, size * 3, nullable_lists ? null_count : 0,
-                            nullable_elements, &lists));
-    std::shared_ptr<ListArray> parent_lists;
-    ASSERT_OK(MakeListArray(lists, size, nullable_parent_lists ? null_count : 0,
-                            nullable_lists, &parent_lists));
-    *out = MakeSimpleTable(parent_lists, nullable_parent_lists);
-  }
-
-  void ReadAndCheckSingleColumnTable(const std::shared_ptr<Array>& values) {
-    std::shared_ptr<::arrow::Table> out;
-    std::unique_ptr<FileReader> reader;
-    ReaderFromSink(&reader);
-    ReadTableFromFile(std::move(reader), &out);
-    ASSERT_EQ(1, out->num_columns());
-    ASSERT_EQ(values->length(), out->num_rows());
-
-    std::shared_ptr<ChunkedArray> chunked_array = out->column(0)->data();
-    ASSERT_EQ(1, chunked_array->num_chunks());
-    auto result = chunked_array->chunk(0);
-
-    internal::AssertArraysEqual(*values, *result);
-  }
-
-  void CheckRoundTrip(const std::shared_ptr<Table>& table) {
-    CheckSimpleRoundtrip(table, table->num_rows());
-  }
-
-  template <typename ArrayType>
-  void WriteColumn(const std::shared_ptr<GroupNode>& schema,
-                   const std::shared_ptr<ArrayType>& values) {
-    FileWriter writer(::arrow::default_memory_pool(), MakeWriter(schema));
-    ASSERT_OK_NO_THROW(writer.NewRowGroup(values->length()));
-    ASSERT_OK_NO_THROW(writer.WriteColumnChunk(*values));
-    ASSERT_OK_NO_THROW(writer.Close());
-    // writer.Close() should be idempotent
-    ASSERT_OK_NO_THROW(writer.Close());
-  }
-
-  std::shared_ptr<InMemoryOutputStream> sink_;
-};
-
-// We have separate tests for UInt32Type as this is currently the only type
-// where a roundtrip does not yield the identical Array structure.
-// There we write an UInt32 Array but receive an Int64 Array as result for
-// Parquet version 1.0.
-
-typedef ::testing::Types<
-    ::arrow::BooleanType, ::arrow::UInt8Type, ::arrow::Int8Type, ::arrow::UInt16Type,
-    ::arrow::Int16Type, ::arrow::Int32Type, ::arrow::UInt64Type, ::arrow::Int64Type,
-    ::arrow::Date32Type, ::arrow::FloatType, ::arrow::DoubleType, ::arrow::StringType,
-    ::arrow::BinaryType, ::arrow::FixedSizeBinaryType, DecimalWithPrecisionAndScale<1>,
-    DecimalWithPrecisionAndScale<3>, DecimalWithPrecisionAndScale<5>,
-    DecimalWithPrecisionAndScale<7>, DecimalWithPrecisionAndScale<10>,
-    DecimalWithPrecisionAndScale<12>, DecimalWithPrecisionAndScale<15>,
-    DecimalWithPrecisionAndScale<17>, DecimalWithPrecisionAndScale<19>,
-    DecimalWithPrecisionAndScale<22>, DecimalWithPrecisionAndScale<23>,
-    DecimalWithPrecisionAndScale<24>, DecimalWithPrecisionAndScale<27>,
-    DecimalWithPrecisionAndScale<29>, DecimalWithPrecisionAndScale<32>,
-    DecimalWithPrecisionAndScale<34>, DecimalWithPrecisionAndScale<38>>
-    TestTypes;
-
-TYPED_TEST_CASE(TestParquetIO, TestTypes);
-
-TYPED_TEST(TestParquetIO, SingleColumnRequiredWrite) {
-  std::shared_ptr<Array> values;
-  ASSERT_OK(NonNullArray<TypeParam>(SMALL_SIZE, &values));
-
-  std::shared_ptr<GroupNode> schema =
-      MakeSimpleSchema(*values->type(), Repetition::REQUIRED);
-  ASSERT_NO_FATAL_FAILURE(this->WriteColumn(schema, values));
-
-  ASSERT_NO_FATAL_FAILURE(this->ReadAndCheckSingleColumnFile(*values));
-}
-
-TYPED_TEST(TestParquetIO, SingleColumnTableRequiredWrite) {
-  std::shared_ptr<Array> values;
-  ASSERT_OK(NonNullArray<TypeParam>(SMALL_SIZE, &values));
-  std::shared_ptr<Table> table = MakeSimpleTable(values, false);
-  this->sink_ = std::make_shared<InMemoryOutputStream>();
-  ASSERT_OK_NO_THROW(WriteTable(*table, ::arrow::default_memory_pool(), this->sink_,
-                                values->length(), default_writer_properties()));
-
-  std::shared_ptr<Table> out;
-  std::unique_ptr<FileReader> reader;
-  ASSERT_NO_FATAL_FAILURE(this->ReaderFromSink(&reader));
-  ASSERT_NO_FATAL_FAILURE(this->ReadTableFromFile(std::move(reader), &out));
-  ASSERT_EQ(1, out->num_columns());
-  ASSERT_EQ(100, out->num_rows());
-
-  std::shared_ptr<ChunkedArray> chunked_array = out->column(0)->data();
-  ASSERT_EQ(1, chunked_array->num_chunks());
-
-  internal::AssertArraysEqual(*values, *chunked_array->chunk(0));
-}
-
-TYPED_TEST(TestParquetIO, SingleColumnOptionalReadWrite) {
-  // This also tests max_definition_level = 1
-  std::shared_ptr<Array> values;
-
-  ASSERT_OK(NullableArray<TypeParam>(SMALL_SIZE, 10, kDefaultSeed, &values));
-
-  std::shared_ptr<GroupNode> schema =
-      MakeSimpleSchema(*values->type(), Repetition::OPTIONAL);
-  ASSERT_NO_FATAL_FAILURE(this->WriteColumn(schema, values));
-
-  ASSERT_NO_FATAL_FAILURE(this->ReadAndCheckSingleColumnFile(*values));
-}
-
-TYPED_TEST(TestParquetIO, SingleColumnOptionalDictionaryWrite) {
-  // Skip tests for BOOL as we don't create dictionaries for it.
-  if (TypeParam::type_id == ::arrow::Type::BOOL) {
-    return;
-  }
-
-  std::shared_ptr<Array> values;
-
-  ASSERT_OK(NullableArray<TypeParam>(SMALL_SIZE, 10, kDefaultSeed, &values));
-
-  Datum out;
-  FunctionContext ctx(default_memory_pool());
-  ASSERT_OK(DictionaryEncode(&ctx, Datum(values), &out));
-  std::shared_ptr<Array> dict_values = MakeArray(out.array());
-  std::shared_ptr<GroupNode> schema =
-      MakeSimpleSchema(*dict_values->type(), Repetition::OPTIONAL);
-  ASSERT_NO_FATAL_FAILURE(this->WriteColumn(schema, dict_values));
-
-  ASSERT_NO_FATAL_FAILURE(this->ReadAndCheckSingleColumnFile(*values));
-}
-
-TYPED_TEST(TestParquetIO, SingleColumnRequiredSliceWrite) {
-  std::shared_ptr<Array> values;
-  ASSERT_OK(NonNullArray<TypeParam>(2 * SMALL_SIZE, &values));
-  std::shared_ptr<GroupNode> schema =
-      MakeSimpleSchema(*values->type(), Repetition::REQUIRED);
-
-  std::shared_ptr<Array> sliced_values = values->Slice(SMALL_SIZE / 2, SMALL_SIZE);
-  ASSERT_NO_FATAL_FAILURE(this->WriteColumn(schema, sliced_values));
-  ASSERT_NO_FATAL_FAILURE(this->ReadAndCheckSingleColumnFile(*sliced_values));
-
-  // Slice offset 1 higher
-  sliced_values = values->Slice(SMALL_SIZE / 2 + 1, SMALL_SIZE);
-  ASSERT_NO_FATAL_FAILURE(this->WriteColumn(schema, sliced_values));
-  ASSERT_NO_FATAL_FAILURE(this->ReadAndCheckSingleColumnFile(*sliced_values));
-}
-
-TYPED_TEST(TestParquetIO, SingleColumnOptionalSliceWrite) {
-  std::shared_ptr<Array> values;
-  ASSERT_OK(NullableArray<TypeParam>(2 * SMALL_SIZE, SMALL_SIZE, kDefaultSeed, &values));
-  std::shared_ptr<GroupNode> schema =
-      MakeSimpleSchema(*values->type(), Repetition::OPTIONAL);
-
-  std::shared_ptr<Array> sliced_values = values->Slice(SMALL_SIZE / 2, SMALL_SIZE);
-  ASSERT_NO_FATAL_FAILURE(this->WriteColumn(schema, sliced_values));
-  ASSERT_NO_FATAL_FAILURE(this->ReadAndCheckSingleColumnFile(*sliced_values));
-
-  // Slice offset 1 higher, thus different null bitmap.
-  sliced_values = values->Slice(SMALL_SIZE / 2 + 1, SMALL_SIZE);
-  ASSERT_NO_FATAL_FAILURE(this->WriteColumn(schema, sliced_values));
-  ASSERT_NO_FATAL_FAILURE(this->ReadAndCheckSingleColumnFile(*sliced_values));
-}
-
-TYPED_TEST(TestParquetIO, SingleColumnTableOptionalReadWrite) {
-  // This also tests max_definition_level = 1
-  std::shared_ptr<Array> values;
-
-  ASSERT_OK(NullableArray<TypeParam>(SMALL_SIZE, 10, kDefaultSeed, &values));
-  std::shared_ptr<Table> table = MakeSimpleTable(values, true);
-  ASSERT_NO_FATAL_FAILURE(this->CheckRoundTrip(table));
-}
-
-TYPED_TEST(TestParquetIO, SingleEmptyListsColumnReadWrite) {
-  std::shared_ptr<Table> table;
-  ASSERT_NO_FATAL_FAILURE(this->PrepareEmptyListsTable(SMALL_SIZE, &table));
-  ASSERT_NO_FATAL_FAILURE(this->CheckRoundTrip(table));
-}
-
-TYPED_TEST(TestParquetIO, SingleNullableListNullableColumnReadWrite) {
-  std::shared_ptr<Table> table;
-  ASSERT_NO_FATAL_FAILURE(this->PrepareListTable(SMALL_SIZE, true, true, 10, &table));
-  ASSERT_NO_FATAL_FAILURE(this->CheckRoundTrip(table));
-}
-
-TYPED_TEST(TestParquetIO, SingleRequiredListNullableColumnReadWrite) {
-  std::shared_ptr<Table> table;
-  ASSERT_NO_FATAL_FAILURE(this->PrepareListTable(SMALL_SIZE, false, true, 10, &table));
-  ASSERT_NO_FATAL_FAILURE(this->CheckRoundTrip(table));
-}
-
-TYPED_TEST(TestParquetIO, SingleNullableListRequiredColumnReadWrite) {
-  std::shared_ptr<Table> table;
-  ASSERT_NO_FATAL_FAILURE(this->PrepareListTable(SMALL_SIZE, true, false, 10, &table));
-  ASSERT_NO_FATAL_FAILURE(this->CheckRoundTrip(table));
-}
-
-TYPED_TEST(TestParquetIO, SingleRequiredListRequiredColumnReadWrite) {
-  std::shared_ptr<Table> table;
-  ASSERT_NO_FATAL_FAILURE(this->PrepareListTable(SMALL_SIZE, false, false, 0, &table));
-  ASSERT_NO_FATAL_FAILURE(this->CheckRoundTrip(table));
-}
-
-TYPED_TEST(TestParquetIO, SingleNullableListRequiredListRequiredColumnReadWrite) {
-  std::shared_ptr<Table> table;
-  ASSERT_NO_FATAL_FAILURE(
-      this->PrepareListOfListTable(SMALL_SIZE, true, false, false, 0, &table));
-  ASSERT_NO_FATAL_FAILURE(this->CheckRoundTrip(table));
-}
-
-TYPED_TEST(TestParquetIO, SingleColumnRequiredChunkedWrite) {
-  std::shared_ptr<Array> values;
-  ASSERT_OK(NonNullArray<TypeParam>(SMALL_SIZE, &values));
-  int64_t chunk_size = values->length() / 4;
-
-  std::shared_ptr<GroupNode> schema =
-      MakeSimpleSchema(*values->type(), Repetition::REQUIRED);
-  FileWriter writer(default_memory_pool(), this->MakeWriter(schema));
-  for (int i = 0; i < 4; i++) {
-    ASSERT_OK_NO_THROW(writer.NewRowGroup(chunk_size));
-    std::shared_ptr<Array> sliced_array = values->Slice(i * chunk_size, chunk_size);
-    ASSERT_OK_NO_THROW(writer.WriteColumnChunk(*sliced_array));
-  }
-  ASSERT_OK_NO_THROW(writer.Close());
-
-  ASSERT_NO_FATAL_FAILURE(this->ReadAndCheckSingleColumnFile(*values));
-}
-
-TYPED_TEST(TestParquetIO, SingleColumnTableRequiredChunkedWrite) {
-  std::shared_ptr<Array> values;
-  ASSERT_OK(NonNullArray<TypeParam>(LARGE_SIZE, &values));
-  std::shared_ptr<Table> table = MakeSimpleTable(values, false);
-  this->sink_ = std::make_shared<InMemoryOutputStream>();
-  ASSERT_OK_NO_THROW(WriteTable(*table, default_memory_pool(), this->sink_, 512,
-                                default_writer_properties()));
-
-  ASSERT_NO_FATAL_FAILURE(this->ReadAndCheckSingleColumnTable(values));
-}
-
-TYPED_TEST(TestParquetIO, SingleColumnTableRequiredChunkedWriteArrowIO) {
-  std::shared_ptr<Array> values;
-  ASSERT_OK(NonNullArray<TypeParam>(LARGE_SIZE, &values));
-  std::shared_ptr<Table> table = MakeSimpleTable(values, false);
-  this->sink_ = std::make_shared<InMemoryOutputStream>();
-  auto buffer = AllocateBuffer();
-
-  {
-    // BufferOutputStream closed on gc
-    auto arrow_sink_ = std::make_shared<::arrow::io::BufferOutputStream>(buffer);
-    ASSERT_OK_NO_THROW(WriteTable(*table, default_memory_pool(), arrow_sink_, 512,
-                                  default_writer_properties()));
-
-    // XXX: Remove this after ARROW-455 completed
-    ASSERT_OK(arrow_sink_->Close());
-  }
-
-  auto pbuffer = std::make_shared<Buffer>(buffer->data(), buffer->size());
-
-  auto source = std::make_shared<BufferReader>(pbuffer);
-  std::shared_ptr<::arrow::Table> out;
-  std::unique_ptr<FileReader> reader;
-  ASSERT_OK_NO_THROW(OpenFile(source, ::arrow::default_memory_pool(), &reader));
-  ASSERT_NO_FATAL_FAILURE(this->ReadTableFromFile(std::move(reader), &out));
-  ASSERT_EQ(1, out->num_columns());
-  ASSERT_EQ(values->length(), out->num_rows());
-
-  std::shared_ptr<ChunkedArray> chunked_array = out->column(0)->data();
-  ASSERT_EQ(1, chunked_array->num_chunks());
-
-  internal::AssertArraysEqual(*values, *chunked_array->chunk(0));
-}
-
-TYPED_TEST(TestParquetIO, SingleColumnOptionalChunkedWrite) {
-  int64_t chunk_size = SMALL_SIZE / 4;
-  std::shared_ptr<Array> values;
-
-  ASSERT_OK(NullableArray<TypeParam>(SMALL_SIZE, 10, kDefaultSeed, &values));
-
-  std::shared_ptr<GroupNode> schema =
-      MakeSimpleSchema(*values->type(), Repetition::OPTIONAL);
-  FileWriter writer(::arrow::default_memory_pool(), this->MakeWriter(schema));
-  for (int i = 0; i < 4; i++) {
-    ASSERT_OK_NO_THROW(writer.NewRowGroup(chunk_size));
-    std::shared_ptr<Array> sliced_array = values->Slice(i * chunk_size, chunk_size);
-    ASSERT_OK_NO_THROW(writer.WriteColumnChunk(*sliced_array));
-  }
-  ASSERT_OK_NO_THROW(writer.Close());
-
-  ASSERT_NO_FATAL_FAILURE(this->ReadAndCheckSingleColumnFile(*values));
-}
-
-TYPED_TEST(TestParquetIO, SingleColumnTableOptionalChunkedWrite) {
-  // This also tests max_definition_level = 1
-  std::shared_ptr<Array> values;
-
-  ASSERT_OK(NullableArray<TypeParam>(LARGE_SIZE, 100, kDefaultSeed, &values));
-  std::shared_ptr<Table> table = MakeSimpleTable(values, true);
-  this->sink_ = std::make_shared<InMemoryOutputStream>();
-  ASSERT_OK_NO_THROW(WriteTable(*table, ::arrow::default_memory_pool(), this->sink_, 512,
-                                default_writer_properties()));
-
-  ASSERT_NO_FATAL_FAILURE(this->ReadAndCheckSingleColumnTable(values));
-}
-
-TYPED_TEST(TestParquetIO, FileMetaDataWrite) {
-  std::shared_ptr<Array> values;
-  ASSERT_OK(NonNullArray<TypeParam>(SMALL_SIZE, &values));
-  std::shared_ptr<Table> table = MakeSimpleTable(values, false);
-  this->sink_ = std::make_shared<InMemoryOutputStream>();
-  ASSERT_OK_NO_THROW(WriteTable(*table, ::arrow::default_memory_pool(), this->sink_,
-                                values->length(), default_writer_properties()));
-
-  std::unique_ptr<FileReader> reader;
-  ASSERT_NO_FATAL_FAILURE(this->ReaderFromSink(&reader));
-  auto metadata = reader->parquet_reader()->metadata();
-  ASSERT_EQ(1, metadata->num_columns());
-  ASSERT_EQ(100, metadata->num_rows());
-
-  this->sink_ = std::make_shared<InMemoryOutputStream>();
-
-  ASSERT_OK_NO_THROW(::parquet::arrow::WriteFileMetaData(*metadata, this->sink_.get()));
-
-  ASSERT_NO_FATAL_FAILURE(this->ReaderFromSink(&reader));
-  auto metadata_written = reader->parquet_reader()->metadata();
-  ASSERT_EQ(metadata->size(), metadata_written->size());
-  ASSERT_EQ(metadata->num_row_groups(), metadata_written->num_row_groups());
-  ASSERT_EQ(metadata->num_rows(), metadata_written->num_rows());
-  ASSERT_EQ(metadata->num_columns(), metadata_written->num_columns());
-  ASSERT_EQ(metadata->RowGroup(0)->num_rows(), metadata_written->RowGroup(0)->num_rows());
-}
-
-using TestInt96ParquetIO = TestParquetIO<::arrow::TimestampType>;
-
-TEST_F(TestInt96ParquetIO, ReadIntoTimestamp) {
-  // This test explicitly tests the conversion from an Impala-style timestamp
-  // to a nanoseconds-since-epoch one.
-
-  // 2nd January 1970, 11:35min 145738543ns
-  Int96 day;
-  day.value[2] = UINT32_C(2440589);
-  int64_t seconds = (11 * 60 + 35) * 60;
-  *(reinterpret_cast<int64_t*>(&(day.value))) =
-      seconds * INT64_C(1000) * INT64_C(1000) * INT64_C(1000) + 145738543;
-  // Compute the corresponding nanosecond timestamp
-  struct tm datetime;
-  memset(&datetime, 0, sizeof(struct tm));
-  datetime.tm_year = 70;
-  datetime.tm_mon = 0;
-  datetime.tm_mday = 2;
-  datetime.tm_hour = 11;
-  datetime.tm_min = 35;
-  struct tm epoch;
-  memset(&epoch, 0, sizeof(struct tm));
-
-  epoch.tm_year = 70;
-  epoch.tm_mday = 1;
-  // Nanoseconds since the epoch
-  int64_t val = lrint(difftime(mktime(&datetime), mktime(&epoch))) * INT64_C(1000000000);
-  val += 145738543;
-
-  std::vector<std::shared_ptr<schema::Node>> fields(
-      {schema::PrimitiveNode::Make("int96", Repetition::REQUIRED, ParquetType::INT96)});
-  std::shared_ptr<schema::GroupNode> schema = std::static_pointer_cast<GroupNode>(
-      schema::GroupNode::Make("schema", Repetition::REQUIRED, fields));
-
-  // We cannot write this column with Arrow, so we have to use the plain parquet-cpp API
-  // to write an Int96 file.
-  this->sink_ = std::make_shared<InMemoryOutputStream>();
-  auto writer = ParquetFileWriter::Open(this->sink_, schema);
-  RowGroupWriter* rg_writer = writer->AppendRowGroup();
-  ColumnWriter* c_writer = rg_writer->NextColumn();
-  auto typed_writer = dynamic_cast<TypedColumnWriter<Int96Type>*>(c_writer);
-  ASSERT_NE(typed_writer, nullptr);
-  typed_writer->WriteBatch(1, nullptr, nullptr, &day);
-  c_writer->Close();
-  rg_writer->Close();
-  writer->Close();
-
-  ::arrow::TimestampBuilder builder(::arrow::timestamp(TimeUnit::NANO),
-                                    ::arrow::default_memory_pool());
-  ASSERT_OK(builder.Append(val));
-  std::shared_ptr<Array> values;
-  ASSERT_OK(builder.Finish(&values));
-  ASSERT_NO_FATAL_FAILURE(this->ReadAndCheckSingleColumnFile(*values));
-}
-
-using TestUInt32ParquetIO = TestParquetIO<::arrow::UInt32Type>;
-
-TEST_F(TestUInt32ParquetIO, Parquet_2_0_Compability) {
-  // This also tests max_definition_level = 1
-  std::shared_ptr<Array> values;
-
-  ASSERT_OK(NullableArray<::arrow::UInt32Type>(LARGE_SIZE, 100, kDefaultSeed, &values));
-  std::shared_ptr<Table> table = MakeSimpleTable(values, true);
-
-  // Parquet 2.0 roundtrip should yield an uint32_t column again
-  this->sink_ = std::make_shared<InMemoryOutputStream>();
-  std::shared_ptr<::parquet::WriterProperties> properties =
-      ::parquet::WriterProperties::Builder()
-          .version(ParquetVersion::PARQUET_2_0)
-          ->build();
-  ASSERT_OK_NO_THROW(
-      WriteTable(*table, default_memory_pool(), this->sink_, 512, properties));
-  ASSERT_NO_FATAL_FAILURE(this->ReadAndCheckSingleColumnTable(values));
-}
-
-TEST_F(TestUInt32ParquetIO, Parquet_1_0_Compability) {
-  // This also tests max_definition_level = 1
-  std::shared_ptr<Array> arr;
-  ASSERT_OK(NullableArray<::arrow::UInt32Type>(LARGE_SIZE, 100, kDefaultSeed, &arr));
-
-  std::shared_ptr<::arrow::UInt32Array> values =
-      std::dynamic_pointer_cast<::arrow::UInt32Array>(arr);
-
-  std::shared_ptr<Table> table = MakeSimpleTable(values, true);
-
-  // Parquet 1.0 returns an int64_t column as there is no way to tell a Parquet 1.0
-  // reader that a column is unsigned.
-  this->sink_ = std::make_shared<InMemoryOutputStream>();
-  std::shared_ptr<::parquet::WriterProperties> properties =
-      ::parquet::WriterProperties::Builder()
-          .version(ParquetVersion::PARQUET_1_0)
-          ->build();
-  ASSERT_OK_NO_THROW(
-      WriteTable(*table, ::arrow::default_memory_pool(), this->sink_, 512, properties));
-
-  std::shared_ptr<ResizableBuffer> int64_data = AllocateBuffer();
-  {
-    ASSERT_OK(int64_data->Resize(sizeof(int64_t) * values->length()));
-    auto int64_data_ptr = reinterpret_cast<int64_t*>(int64_data->mutable_data());
-    auto uint32_data_ptr = reinterpret_cast<const uint32_t*>(values->values()->data());
-    const auto cast_uint32_to_int64 = [](uint32_t value) {
-      return static_cast<int64_t>(value);
-    };
-    std::transform(uint32_data_ptr, uint32_data_ptr + values->length(), int64_data_ptr,
-                   cast_uint32_to_int64);
-  }
-
-  std::vector<std::shared_ptr<Buffer>> buffers{values->null_bitmap(), int64_data};
-  auto arr_data = std::make_shared<::arrow::ArrayData>(::arrow::int64(), values->length(),
-                                                       buffers, values->null_count());
-  std::shared_ptr<Array> expected_values = MakeArray(arr_data);
-  ASSERT_NE(expected_values, NULLPTR);
-
-  const auto& expected = static_cast<const ::arrow::Int64Array&>(*expected_values);
-  ASSERT_GT(values->length(), 0);
-  ASSERT_EQ(values->length(), expected.length());
-
-  // TODO(phillipc): Is there a better way to compare these two arrays?
-  // AssertArraysEqual requires the same type, but we only care about values in this case
-  for (int i = 0; i < expected.length(); ++i) {
-    const bool value_is_valid = values->IsValid(i);
-    const bool expected_value_is_valid = expected.IsValid(i);
-
-    ASSERT_EQ(expected_value_is_valid, value_is_valid);
-
-    if (value_is_valid) {
-      uint32_t value = values->Value(i);
-      int64_t expected_value = expected.Value(i);
-      ASSERT_EQ(expected_value, static_cast<int64_t>(value));
-    }
-  }
-}
-
-using TestStringParquetIO = TestParquetIO<::arrow::StringType>;
-
-TEST_F(TestStringParquetIO, EmptyStringColumnRequiredWrite) {
-  std::shared_ptr<Array> values;
-  ::arrow::StringBuilder builder;
-  for (size_t i = 0; i < SMALL_SIZE; i++) {
-    ASSERT_OK(builder.Append(""));
-  }
-  ASSERT_OK(builder.Finish(&values));
-  std::shared_ptr<Table> table = MakeSimpleTable(values, false);
-  this->sink_ = std::make_shared<InMemoryOutputStream>();
-  ASSERT_OK_NO_THROW(WriteTable(*table, ::arrow::default_memory_pool(), this->sink_,
-                                values->length(), default_writer_properties()));
-
-  std::shared_ptr<Table> out;
-  std::unique_ptr<FileReader> reader;
-  ASSERT_NO_FATAL_FAILURE(this->ReaderFromSink(&reader));
-  ASSERT_NO_FATAL_FAILURE(this->ReadTableFromFile(std::move(reader), &out));
-  ASSERT_EQ(1, out->num_columns());
-  ASSERT_EQ(100, out->num_rows());
-
-  std::shared_ptr<ChunkedArray> chunked_array = out->column(0)->data();
-  ASSERT_EQ(1, chunked_array->num_chunks());
-
-  internal::AssertArraysEqual(*values, *chunked_array->chunk(0));
-}
-
-using TestNullParquetIO = TestParquetIO<::arrow::NullType>;
-
-TEST_F(TestNullParquetIO, NullColumn) {
-  for (int32_t num_rows : {0, SMALL_SIZE}) {
-    std::shared_ptr<Array> values = std::make_shared<::arrow::NullArray>(num_rows);
-    std::shared_ptr<Table> table = MakeSimpleTable(values, true /* nullable */);
-    this->sink_ = std::make_shared<InMemoryOutputStream>();
-
-    const int64_t chunk_size = std::max(static_cast<int64_t>(1), table->num_rows());
-    ASSERT_OK_NO_THROW(WriteTable(*table, ::arrow::default_memory_pool(), this->sink_,
-                                  chunk_size, default_writer_properties()));
-
-    std::shared_ptr<Table> out;
-    std::unique_ptr<FileReader> reader;
-    ASSERT_NO_FATAL_FAILURE(this->ReaderFromSink(&reader));
-    ASSERT_NO_FATAL_FAILURE(this->ReadTableFromFile(std::move(reader), &out));
-    ASSERT_EQ(1, out->num_columns());
-    ASSERT_EQ(num_rows, out->num_rows());
-
-    std::shared_ptr<ChunkedArray> chunked_array = out->column(0)->data();
-    ASSERT_EQ(1, chunked_array->num_chunks());
-    internal::AssertArraysEqual(*values, *chunked_array->chunk(0));
-  }
-}
-
-TEST_F(TestNullParquetIO, NullListColumn) {
-  std::vector<int32_t> offsets1 = {0};
-  std::vector<int32_t> offsets2 = {0, 2, 2, 3, 115};
-  for (std::vector<int32_t> offsets : {offsets1, offsets2}) {
-    std::shared_ptr<Array> offsets_array, values_array, list_array;
-    ::arrow::ArrayFromVector<::arrow::Int32Type, int32_t>(offsets, &offsets_array);
-    values_array = std::make_shared<::arrow::NullArray>(offsets.back());
-    ASSERT_OK(::arrow::ListArray::FromArrays(*offsets_array, *values_array,
-                                             default_memory_pool(), &list_array));
-
-    std::shared_ptr<Table> table = MakeSimpleTable(list_array, false /* nullable */);
-    this->sink_ = std::make_shared<InMemoryOutputStream>();
-
-    const int64_t chunk_size = std::max(static_cast<int64_t>(1), table->num_rows());
-    ASSERT_OK_NO_THROW(WriteTable(*table, ::arrow::default_memory_pool(), this->sink_,
-                                  chunk_size, default_writer_properties()));
-
-    std::shared_ptr<Table> out;
-    std::unique_ptr<FileReader> reader;
-    this->ReaderFromSink(&reader);
-    this->ReadTableFromFile(std::move(reader), &out);
-    ASSERT_EQ(1, out->num_columns());
-    ASSERT_EQ(offsets.size() - 1, out->num_rows());
-
-    std::shared_ptr<ChunkedArray> chunked_array = out->column(0)->data();
-    ASSERT_EQ(1, chunked_array->num_chunks());
-    internal::AssertArraysEqual(*list_array, *chunked_array->chunk(0));
-  }
-}
-
-TEST_F(TestNullParquetIO, NullDictionaryColumn) {
-  std::shared_ptr<Array> values = std::make_shared<::arrow::NullArray>(0);
-  std::shared_ptr<Array> indices =
-      std::make_shared<::arrow::Int8Array>(SMALL_SIZE, nullptr, nullptr, SMALL_SIZE);
-  std::shared_ptr<::arrow::DictionaryType> dict_type =
-      std::make_shared<::arrow::DictionaryType>(::arrow::int8(), values);
-  std::shared_ptr<Array> dict_values =
-      std::make_shared<::arrow::DictionaryArray>(dict_type, indices);
-  std::shared_ptr<Table> table = MakeSimpleTable(dict_values, true);
-  this->sink_ = std::make_shared<InMemoryOutputStream>();
-  ASSERT_OK_NO_THROW(WriteTable(*table, ::arrow::default_memory_pool(), this->sink_,
-                                dict_values->length(), default_writer_properties()));
-
-  std::shared_ptr<Table> out;
-  std::unique_ptr<FileReader> reader;
-  ASSERT_NO_FATAL_FAILURE(this->ReaderFromSink(&reader));
-  ASSERT_NO_FATAL_FAILURE(this->ReadTableFromFile(std::move(reader), &out));
-  ASSERT_EQ(1, out->num_columns());
-  ASSERT_EQ(100, out->num_rows());
-
-  std::shared_ptr<ChunkedArray> chunked_array = out->column(0)->data();
-  ASSERT_EQ(1, chunked_array->num_chunks());
-
-  std::shared_ptr<Array> expected_values =
-      std::make_shared<::arrow::NullArray>(SMALL_SIZE);
-  internal::AssertArraysEqual(*expected_values, *chunked_array->chunk(0));
-}
-
-template <typename T>
-using ParquetCDataType = typename ParquetDataType<T>::c_type;
-
-template <typename T>
-struct c_type_trait {
-  using ArrowCType = typename T::c_type;
-};
-
-template <>
-struct c_type_trait<::arrow::BooleanType> {
-  using ArrowCType = uint8_t;
-};
-
-template <typename TestType>
-class TestPrimitiveParquetIO : public TestParquetIO<TestType> {
- public:
-  typedef typename c_type_trait<TestType>::ArrowCType T;
-
-  void MakeTestFile(std::vector<T>& values, int num_chunks,
-                    std::unique_ptr<FileReader>* reader) {
-    TestType dummy;
-
-    std::shared_ptr<GroupNode> schema = MakeSimpleSchema(dummy, Repetition::REQUIRED);
-    std::unique_ptr<ParquetFileWriter> file_writer = this->MakeWriter(schema);
-    size_t chunk_size = values.size() / num_chunks;
-    // Convert to Parquet's expected physical type
-    std::vector<uint8_t> values_buffer(sizeof(ParquetCDataType<TestType>) *
-                                       values.size());
-    auto values_parquet =
-        reinterpret_cast<ParquetCDataType<TestType>*>(values_buffer.data());
-    std::copy(values.cbegin(), values.cend(), values_parquet);
-    for (int i = 0; i < num_chunks; i++) {
-      auto row_group_writer = file_writer->AppendRowGroup();
-      auto column_writer =
-          static_cast<ParquetWriter<TestType>*>(row_group_writer->NextColumn());
-      ParquetCDataType<TestType>* data = values_parquet + i * chunk_size;
-      column_writer->WriteBatch(chunk_size, nullptr, nullptr, data);
-      column_writer->Close();
-      row_group_writer->Close();
-    }
-    file_writer->Close();
-    this->ReaderFromSink(reader);
-  }
-
-  void CheckSingleColumnRequiredTableRead(int num_chunks) {
-    std::vector<T> values(SMALL_SIZE, test_traits<TestType>::value);
-    std::unique_ptr<FileReader> file_reader;
-    ASSERT_NO_FATAL_FAILURE(MakeTestFile(values, num_chunks, &file_reader));
-
-    std::shared_ptr<Table> out;
-    this->ReadTableFromFile(std::move(file_reader), &out);
-    ASSERT_EQ(1, out->num_columns());
-    ASSERT_EQ(SMALL_SIZE, out->num_rows());
-
-    std::shared_ptr<ChunkedArray> chunked_array = out->column(0)->data();
-    ASSERT_EQ(1, chunked_array->num_chunks());
-    ExpectArrayT<TestType>(values.data(), chunked_array->chunk(0).get());
-  }
-
-  void CheckSingleColumnRequiredRead(int num_chunks) {
-    std::vector<T> values(SMALL_SIZE, test_traits<TestType>::value);
-    std::unique_ptr<FileReader> file_reader;
-    ASSERT_NO_FATAL_FAILURE(MakeTestFile(values, num_chunks, &file_reader));
-
-    std::shared_ptr<Array> out;
-    this->ReadSingleColumnFile(std::move(file_reader), &out);
-
-    ExpectArrayT<TestType>(values.data(), out.get());
-  }
-};
-
-typedef ::testing::Types<::arrow::BooleanType, ::arrow::UInt8Type, ::arrow::Int8Type,
-                         ::arrow::UInt16Type, ::arrow::Int16Type, ::arrow::UInt32Type,
-                         ::arrow::Int32Type, ::arrow::UInt64Type, ::arrow::Int64Type,
-                         ::arrow::FloatType, ::arrow::DoubleType>
-    PrimitiveTestTypes;
-
-TYPED_TEST_CASE(TestPrimitiveParquetIO, PrimitiveTestTypes);
-
-TYPED_TEST(TestPrimitiveParquetIO, SingleColumnRequiredRead) {
-  ASSERT_NO_FATAL_FAILURE(this->CheckSingleColumnRequiredRead(1));
-}
-
-TYPED_TEST(TestPrimitiveParquetIO, SingleColumnRequiredTableRead) {
-  ASSERT_NO_FATAL_FAILURE(this->CheckSingleColumnRequiredTableRead(1));
-}
-
-TYPED_TEST(TestPrimitiveParquetIO, SingleColumnRequiredChunkedRead) {
-  ASSERT_NO_FATAL_FAILURE(this->CheckSingleColumnRequiredRead(4));
-}
-
-TYPED_TEST(TestPrimitiveParquetIO, SingleColumnRequiredChunkedTableRead) {
-  ASSERT_NO_FATAL_FAILURE(this->CheckSingleColumnRequiredTableRead(4));
-}
-
-void MakeDateTimeTypesTable(std::shared_ptr<Table>* out, bool nanos_as_micros = false) {
-  using ::arrow::ArrayFromVector;
-
-  std::vector<bool> is_valid = {true, true, true, false, true, true};
-
-  // These are only types that roundtrip without modification
-  auto f0 = field("f0", ::arrow::date32());
-  auto f1 = field("f1", ::arrow::timestamp(TimeUnit::MILLI));
-  auto f2 = field("f2", ::arrow::timestamp(TimeUnit::MICRO));
-  std::shared_ptr<::arrow::Field> f3;
-  if (nanos_as_micros) {
-    f3 = field("f3", ::arrow::timestamp(TimeUnit::MICRO));
-  } else {
-    f3 = field("f3", ::arrow::timestamp(TimeUnit::NANO));
-  }
-  auto f4 = field("f4", ::arrow::time32(TimeUnit::MILLI));
-  auto f5 = field("f5", ::arrow::time64(TimeUnit::MICRO));
-  std::shared_ptr<::arrow::Schema> schema(new ::arrow::Schema({f0, f1, f2, f3, f4, f5}));
-
-  std::vector<int32_t> t32_values = {1489269000, 1489270000, 1489271000,
-                                     1489272000, 1489272000, 1489273000};
-  std::vector<int64_t> t64_values = {1489269000000, 1489270000000, 1489271000000,
-                                     1489272000000, 1489272000000, 1489273000000};
-  std::vector<int64_t> t64_us_values = {1489269000, 1489270000, 1489271000,
-                                        1489272000, 1489272000, 1489273000};
-
-  std::shared_ptr<Array> a0, a1, a2, a3, a4, a5;
-  ArrayFromVector<::arrow::Date32Type, int32_t>(f0->type(), is_valid, t32_values, &a0);
-  ArrayFromVector<::arrow::TimestampType, int64_t>(f1->type(), is_valid, t64_values, &a1);
-  ArrayFromVector<::arrow::TimestampType, int64_t>(f2->type(), is_valid, t64_values, &a2);
-  if (nanos_as_micros) {
-    ArrayFromVector<::arrow::TimestampType, int64_t>(f3->type(), is_valid, t64_us_values,
-                                                     &a3);
-  } else {
-    ArrayFromVector<::arrow::TimestampType, int64_t>(f3->type(), is_valid, t64_values,
-                                                     &a3);
-  }
-  ArrayFromVector<::arrow::Time32Type, int32_t>(f4->type(), is_valid, t32_values, &a4);
-  ArrayFromVector<::arrow::Time64Type, int64_t>(f5->type(), is_valid, t64_values, &a5);
-
-  std::vector<std::shared_ptr<::arrow::Column>> columns = {
-      std::make_shared<Column>("f0", a0), std::make_shared<Column>("f1", a1),
-      std::make_shared<Column>("f2", a2), std::make_shared<Column>("f3", a3),
-      std::make_shared<Column>("f4", a4), std::make_shared<Column>("f5", a5)};
-  *out = Table::Make(schema, columns);
-}
-
-TEST(TestArrowReadWrite, DateTimeTypes) {
-  std::shared_ptr<Table> table;
-  MakeDateTimeTypesTable(&table);
-
-  // Use deprecated INT96 type
-  std::shared_ptr<Table> result;
-  ASSERT_NO_FATAL_FAILURE(DoSimpleRoundtrip(
-      table, false /* use_threads */, table->num_rows(), {}, &result,
-      ArrowWriterProperties::Builder().enable_deprecated_int96_timestamps()->build()));
-
-  ASSERT_NO_FATAL_FAILURE(::arrow::AssertTablesEqual(*table, *result));
-
-  // Cast nanaoseconds to microseconds and use INT64 physical type
-  ASSERT_NO_FATAL_FAILURE(
-      DoSimpleRoundtrip(table, false /* use_threads */, table->num_rows(), {}, &result));
-  std::shared_ptr<Table> expected;
-  MakeDateTimeTypesTable(&table, true);
-
-  ASSERT_NO_FATAL_FAILURE(::arrow::AssertTablesEqual(*table, *result));
-}
-
-TEST(TestArrowReadWrite, CoerceTimestamps) {
-  using ::arrow::ArrayFromVector;
-  using ::arrow::field;
-
-  // PARQUET-1078, coerce Arrow timestamps to either TIMESTAMP_MILLIS or TIMESTAMP_MICROS
-  std::vector<bool> is_valid = {true, true, true, false, true, true};
-
-  auto t_s = ::arrow::timestamp(TimeUnit::SECOND);
-  auto t_ms = ::arrow::timestamp(TimeUnit::MILLI);
-  auto t_us = ::arrow::timestamp(TimeUnit::MICRO);
-  auto t_ns = ::arrow::timestamp(TimeUnit::NANO);
-
-  std::vector<int64_t> s_values = {1489269, 1489270, 1489271, 1489272, 1489272, 1489273};
-  std::vector<int64_t> ms_values = {1489269000, 1489270000, 1489271000,
-                                    1489272001, 1489272000, 1489273000};
-  std::vector<int64_t> us_values = {1489269000000, 1489270000000, 1489271000000,
-                                    1489272000001, 1489272000000, 1489273000000};
-  std::vector<int64_t> ns_values = {1489269000000000LL, 1489270000000000LL,
-                                    1489271000000000LL, 1489272000000001LL,
-                                    1489272000000000LL, 1489273000000000LL};
-
-  std::shared_ptr<Array> a_s, a_ms, a_us, a_ns;
-  ArrayFromVector<::arrow::TimestampType, int64_t>(t_s, is_valid, s_values, &a_s);
-  ArrayFromVector<::arrow::TimestampType, int64_t>(t_ms, is_valid, ms_values, &a_ms);
-  ArrayFromVector<::arrow::TimestampType, int64_t>(t_us, is_valid, us_values, &a_us);
-  ArrayFromVector<::arrow::TimestampType, int64_t>(t_ns, is_valid, ns_values, &a_ns);
-
-  // Input table, all data as is
-  auto s1 = std::shared_ptr<::arrow::Schema>(
-      new ::arrow::Schema({field("f_s", t_s), field("f_ms", t_ms), field("f_us", t_us),
-                           field("f_ns", t_ns)}));
-  auto input = Table::Make(
-      s1,
-      {std::make_shared<Column>("f_s", a_s), std::make_shared<Column>("f_ms", a_ms),
-       std::make_shared<Column>("f_us", a_us), std::make_shared<Column>("f_ns", a_ns)});
-
-  // Result when coercing to milliseconds
-  auto s2 = std::shared_ptr<::arrow::Schema>(
-      new ::arrow::Schema({field("f_s", t_ms), field("f_ms", t_ms), field("f_us", t_ms),
-                           field("f_ns", t_ms)}));
-  auto ex_milli_result = Table::Make(
-      s2,
-      {std::make_shared<Column>("f_s", a_ms), std::make_shared<Column>("f_ms", a_ms),
-       std::make_shared<Column>("f_us", a_ms), std::make_shared<Column>("f_ns", a_ms)});
-
-  // Result when coercing to microseconds
-  auto s3 = std::shared_ptr<::arrow::Schema>(
-      new ::arrow::Schema({field("f_s", t_us), field("f_ms", t_us), field("f_us", t_us),
-                           field("f_ns", t_us)}));
-  auto ex_micro_result = Table::Make(
-      s3,
-      {std::make_shared<Column>("f_s", a_us), std::make_shared<Column>("f_ms", a_us),
-       std::make_shared<Column>("f_us", a_us), std::make_shared<Column>("f_ns", a_us)});
-
-  std::shared_ptr<Table> milli_result;
-  ASSERT_NO_FATAL_FAILURE(DoSimpleRoundtrip(
-      input, false /* use_threads */, input->num_rows(), {}, &milli_result,
-      ArrowWriterProperties::Builder().coerce_timestamps(TimeUnit::MILLI)->build()));
-
-  ASSERT_NO_FATAL_FAILURE(::arrow::AssertTablesEqual(*ex_milli_result, *milli_result));
-
-  std::shared_ptr<Table> micro_result;
-  ASSERT_NO_FATAL_FAILURE(DoSimpleRoundtrip(
-      input, false /* use_threads */, input->num_rows(), {}, &micro_result,
-      ArrowWriterProperties::Builder().coerce_timestamps(TimeUnit::MICRO)->build()));
-  ASSERT_NO_FATAL_FAILURE(::arrow::AssertTablesEqual(*ex_micro_result, *micro_result));
-}
-
-TEST(TestArrowReadWrite, CoerceTimestampsLosePrecision) {
-  using ::arrow::ArrayFromVector;
-  using ::arrow::field;
-
-  // PARQUET-1078, coerce Arrow timestamps to either TIMESTAMP_MILLIS or TIMESTAMP_MICROS
-  std::vector<bool> is_valid = {true, true, true, false, true, true};
-
-  auto t_s = ::arrow::timestamp(TimeUnit::SECOND);
-  auto t_ms = ::arrow::timestamp(TimeUnit::MILLI);
-  auto t_us = ::arrow::timestamp(TimeUnit::MICRO);
-  auto t_ns = ::arrow::timestamp(TimeUnit::NANO);
-
-  std::vector<int64_t> s_values = {1489269, 1489270, 1489271, 1489272, 1489272, 1489273};
-  std::vector<int64_t> ms_values = {1489269001, 1489270001, 1489271001,
-                                    1489272001, 1489272001, 1489273001};
-  std::vector<int64_t> us_values = {1489269000001, 1489270000001, 1489271000001,
-                                    1489272000001, 1489272000001, 1489273000001};
-  std::vector<int64_t> ns_values = {1489269000000001LL, 1489270000000001LL,
-                                    1489271000000001LL, 1489272000000001LL,
-                                    1489272000000001LL, 1489273000000001LL};
-
-  std::shared_ptr<Array> a_s, a_ms, a_us, a_ns;
-  ArrayFromVector<::arrow::TimestampType, int64_t>(t_s, is_valid, s_values, &a_s);
-  ArrayFromVector<::arrow::TimestampType, int64_t>(t_ms, is_valid, ms_values, &a_ms);
-  ArrayFromVector<::arrow::TimestampType, int64_t>(t_us, is_valid, us_values, &a_us);
-  ArrayFromVector<::arrow::TimestampType, int64_t>(t_ns, is_valid, ns_values, &a_ns);
-
-  auto s1 = std::shared_ptr<::arrow::Schema>(new ::arrow::Schema({field("f_s", t_s)}));
-  auto s2 = std::shared_ptr<::arrow::Schema>(new ::arrow::Schema({field("f_ms", t_ms)}));
-  auto s3 = std::shared_ptr<::arrow::Schema>(new ::arrow::Schema({field("f_us", t_us)}));
-  auto s4 = std::shared_ptr<::arrow::Schema>(new ::arrow::Schema({field("f_ns", t_ns)}));
-
-  auto c1 = std::make_shared<Column>("f_s", a_s);
-  auto c2 = std::make_shared<Column>("f_ms", a_ms);
-  auto c3 = std::make_shared<Column>("f_us", a_us);
-  auto c4 = std::make_shared<Column>("f_ns", a_ns);
-
-  auto t1 = Table::Make(s1, {c1});
-  auto t2 = Table::Make(s2, {c2});
-  auto t3 = Table::Make(s3, {c3});
-  auto t4 = Table::Make(s4, {c4});
-
-  auto sink = std::make_shared<InMemoryOutputStream>();
-
-  // OK to write to millis
-  auto coerce_millis =
-      (ArrowWriterProperties::Builder().coerce_timestamps(TimeUnit::MILLI)->build());
-  ASSERT_OK_NO_THROW(WriteTable(*t1, ::arrow::default_memory_pool(), sink, 10,
-                                default_writer_properties(), coerce_millis));
-  ASSERT_OK_NO_THROW(WriteTable(*t2, ::arrow::default_memory_pool(), sink, 10,
-                                default_writer_properties(), coerce_millis));
-
-  // Loss of precision
-  ASSERT_RAISES(Invalid, WriteTable(*t3, ::arrow::default_memory_pool(), sink, 10,
-                                    default_writer_properties(), coerce_millis));
-  ASSERT_RAISES(Invalid, WriteTable(*t4, ::arrow::default_memory_pool(), sink, 10,
-                                    default_writer_properties(), coerce_millis));
-
-  // OK to write micros to micros
-  auto coerce_micros =
-      (ArrowWriterProperties::Builder().coerce_timestamps(TimeUnit::MICRO)->build());
-  ASSERT_OK_NO_THROW(WriteTable(*t3, ::arrow::default_memory_pool(), sink, 10,
-                                default_writer_properties(), coerce_micros));
-
-  // Loss of precision
-  ASSERT_RAISES(Invalid, WriteTable(*t4, ::arrow::default_memory_pool(), sink, 10,
-                                    default_writer_properties(), coerce_micros));
-}
-
-TEST(TestArrowReadWrite, ConvertedDateTimeTypes) {
-  using ::arrow::ArrayFromVector;
-
-  std::vector<bool> is_valid = {true, true, true, false, true, true};
-
-  auto f0 = field("f0", ::arrow::date64());
-  auto f1 = field("f1", ::arrow::time32(TimeUnit::SECOND));
-  auto f2 = field("f2", ::arrow::date64());
-  auto f3 = field("f3", ::arrow::time32(TimeUnit::SECOND));
-
-  auto schema = ::arrow::schema({f0, f1, f2, f3});
-
-  std::vector<int64_t> a0_values = {1489190400000, 1489276800000, 1489363200000,
-                                    1489449600000, 1489536000000, 1489622400000};
-  std::vector<int32_t> a1_values = {0, 1, 2, 3, 4, 5};
-
-  std::shared_ptr<Array> a0, a1, a0_nonnull, a1_nonnull, x0, x1, x0_nonnull, x1_nonnull;
-
-  ArrayFromVector<::arrow::Date64Type, int64_t>(f0->type(), is_valid, a0_values, &a0);
-  ArrayFromVector<::arrow::Date64Type, int64_t>(f0->type(), a0_values, &a0_nonnull);
-
-  ArrayFromVector<::arrow::Time32Type, int32_t>(f1->type(), is_valid, a1_values, &a1);
-  ArrayFromVector<::arrow::Time32Type, int32_t>(f1->type(), a1_values, &a1_nonnull);
-
-  std::vector<std::shared_ptr<::arrow::Column>> columns = {
-      std::make_shared<Column>("f0", a0), std::make_shared<Column>("f1", a1),
-      std::make_shared<Column>("f2", a0_nonnull),
-      std::make_shared<Column>("f3", a1_nonnull)};
-  auto table = Table::Make(schema, columns);
-
-  // Expected schema and values
-  auto e0 = field("f0", ::arrow::date32());
-  auto e1 = field("f1", ::arrow::time32(TimeUnit::MILLI));
-  auto e2 = field("f2", ::arrow::date32());
-  auto e3 = field("f3", ::arrow::time32(TimeUnit::MILLI));
-  auto ex_schema = ::arrow::schema({e0, e1, e2, e3});
-
-  std::vector<int32_t> x0_values = {17236, 17237, 17238, 17239, 17240, 17241};
-  std::vector<int32_t> x1_values = {0, 1000, 2000, 3000, 4000, 5000};
-  ArrayFromVector<::arrow::Date32Type, int32_t>(e0->type(), is_valid, x0_values, &x0);
-  ArrayFromVector<::arrow::Date32Type, int32_t>(e0->type(), x0_values, &x0_nonnull);
-
-  ArrayFromVector<::arrow::Time32Type, int32_t>(e1->type(), is_valid, x1_values, &x1);
-  ArrayFromVector<::arrow::Time32Type, int32_t>(e1->type(), x1_values, &x1_nonnull);
-
-  std::vector<std::shared_ptr<::arrow::Column>> ex_columns = {
-      std::make_shared<Column>("f0", x0), std::make_shared<Column>("f1", x1),
-      std::make_shared<Column>("f2", x0_nonnull),
-      std::make_shared<Column>("f3", x1_nonnull)};
-  auto ex_table = Table::Make(ex_schema, ex_columns);
-
-  std::shared_ptr<Table> result;
-  ASSERT_NO_FATAL_FAILURE(
-      DoSimpleRoundtrip(table, false /* use_threads */, table->num_rows(), {}, &result));
-
-  ASSERT_NO_FATAL_FAILURE(::arrow::AssertTablesEqual(*ex_table, *result));
-}
-
-// Regression for ARROW-2802
-TEST(TestArrowReadWrite, CoerceTimestampsAndSupportDeprecatedInt96) {
-  using ::arrow::Column;
-  using ::arrow::default_memory_pool;
-  using ::arrow::Field;
-  using ::arrow::Schema;
-  using ::arrow::Table;
-  using ::arrow::TimestampBuilder;
-  using ::arrow::TimestampType;
-  using ::arrow::TimeUnit;
-
-  auto timestamp_type = std::make_shared<TimestampType>(TimeUnit::NANO);
-
-  TimestampBuilder builder(timestamp_type, default_memory_pool());
-  for (std::int64_t ii = 0; ii < 10; ++ii) {
-    ASSERT_OK(builder.Append(1000000000L * ii));
-  }
-  std::shared_ptr<Array> values;
-  ASSERT_OK(builder.Finish(&values));
-
-  std::vector<std::shared_ptr<Field>> fields;
-  auto field = std::make_shared<Field>("nanos", timestamp_type);
-  fields.emplace_back(field);
-
-  auto schema = std::make_shared<Schema>(fields);
-
-  std::vector<std::shared_ptr<Column>> columns;
-  auto column = std::make_shared<Column>("nanos", values);
-  columns.emplace_back(column);
-
-  auto table = Table::Make(schema, columns);
-
-  auto arrow_writer_properties = ArrowWriterProperties::Builder()
-                                     .coerce_timestamps(TimeUnit::MICRO)
-                                     ->enable_deprecated_int96_timestamps()
-                                     ->build();
-
-  std::shared_ptr<Table> result;
-  DoSimpleRoundtrip(table, false /* use_threads */, table->num_rows(), {}, &result,
-                    arrow_writer_properties);
-
-  ASSERT_EQ(table->num_columns(), result->num_columns());
-  ASSERT_EQ(table->num_rows(), result->num_rows());
-
-  auto actual_column = result->column(0);
-  auto data = actual_column->data();
-  auto expected_values =
-      static_cast<::arrow::NumericArray<TimestampType>*>(values.get())->raw_values();
-  for (int ii = 0; ii < data->num_chunks(); ++ii) {
-    auto chunk =
-        static_cast<::arrow::NumericArray<TimestampType>*>(data->chunk(ii).get());
-    auto values = chunk->raw_values();
-    for (int64_t jj = 0; jj < chunk->length(); ++jj, ++expected_values) {
-      // Check that the nanos have been converted to micros
-      ASSERT_EQ(*expected_values / 1000, values[jj]);
-    }
-  }
-}
-
-void MakeDoubleTable(int num_columns, int num_rows, int nchunks,
-                     std::shared_ptr<Table>* out) {
-  std::shared_ptr<::arrow::Column> column;
-  std::vector<std::shared_ptr<::arrow::Column>> columns(num_columns);
-  std::vector<std::shared_ptr<::arrow::Field>> fields(num_columns);
-
-  for (int i = 0; i < num_columns; ++i) {
-    std::vector<std::shared_ptr<Array>> arrays;
-    std::shared_ptr<Array> values;
-    ASSERT_OK(NullableArray<::arrow::DoubleType>(num_rows, num_rows / 10,
-                                                 static_cast<uint32_t>(i), &values));
-    std::stringstream ss;
-    ss << "col" << i;
-
-    for (int j = 0; j < nchunks; ++j) {
-      arrays.push_back(values);
-    }
-    column = MakeColumn(ss.str(), arrays, true);
-
-    columns[i] = column;
-    fields[i] = column->field();
-  }
-  auto schema = std::make_shared<::arrow::Schema>(fields);
-  *out = Table::Make(schema, columns);
-}
-
-void MakeListArray(int num_rows, int max_value_length,
-                   std::shared_ptr<::DataType>* out_type,
-                   std::shared_ptr<Array>* out_array) {
-  std::vector<int32_t> length_draws;
-  randint(num_rows, 0, max_value_length, &length_draws);
-
-  std::vector<int32_t> offset_values;
-
-  // Make sure some of them are length 0
-  int32_t total_elements = 0;
-  for (size_t i = 0; i < length_draws.size(); ++i) {
-    if (length_draws[i] < max_value_length / 10) {
-      length_draws[i] = 0;
-    }
-    offset_values.push_back(total_elements);
-    total_elements += length_draws[i];
-  }
-  offset_values.push_back(total_elements);
-
-  std::vector<int8_t> value_draws;
-  randint(total_elements, 0, 100, &value_draws);
-
-  std::vector<bool> is_valid;
-  random_is_valid(total_elements, 0.1, &is_valid);
-
-  std::shared_ptr<Array> values, offsets;
-  ::arrow::ArrayFromVector<::arrow::Int8Type, int8_t>(::arrow::int8(), is_valid,
-                                                      value_draws, &values);
-  ::arrow::ArrayFromVector<::arrow::Int32Type, int32_t>(offset_values, &offsets);
-
-  ASSERT_OK(::arrow::ListArray::FromArrays(*offsets, *values, default_memory_pool(),
-                                           out_array));
-
-  *out_type = ::arrow::list(::arrow::int8());
-}
-
-TEST(TestArrowReadWrite, MultithreadedRead) {
-  const int num_columns = 20;
-  const int num_rows = 1000;
-  const bool use_threads = true;
-
-  std::shared_ptr<Table> table;
-  ASSERT_NO_FATAL_FAILURE(MakeDoubleTable(num_columns, num_rows, 1, &table));
-
-  std::shared_ptr<Table> result;
-  ASSERT_NO_FATAL_FAILURE(
-      DoSimpleRoundtrip(table, use_threads, table->num_rows(), {}, &result));
-
-  ASSERT_NO_FATAL_FAILURE(::arrow::AssertTablesEqual(*table, *result));
-}
-
-TEST(TestArrowReadWrite, ReadSingleRowGroup) {
-  const int num_columns = 20;
-  const int num_rows = 1000;
-
-  std::shared_ptr<Table> table;
-  ASSERT_NO_FATAL_FAILURE(MakeDoubleTable(num_columns, num_rows, 1, &table));
-
-  std::shared_ptr<Buffer> buffer;
-  ASSERT_NO_FATAL_FAILURE(WriteTableToBuffer(table, num_rows / 2,
-                                             default_arrow_writer_properties(), &buffer));
-
-  std::unique_ptr<FileReader> reader;
-  ASSERT_OK_NO_THROW(OpenFile(std::make_shared<BufferReader>(buffer),
-                              ::arrow::default_memory_pool(),
-                              ::parquet::default_reader_properties(), nullptr, &reader));
-
-  ASSERT_EQ(2, reader->num_row_groups());
-
-  std::shared_ptr<Table> r1, r2, r3, r4;
-  // Read everything
-  ASSERT_OK_NO_THROW(reader->ReadRowGroup(0, &r1));
-  ASSERT_OK_NO_THROW(reader->RowGroup(1)->ReadTable(&r2));
-  ASSERT_OK_NO_THROW(reader->ReadRowGroups({0, 1}, &r3));
-  ASSERT_OK_NO_THROW(reader->ReadRowGroups({1}, &r4));
-
-  std::shared_ptr<Table> concatenated;
-
-  ASSERT_OK(ConcatenateTables({r1, r2}, &concatenated));
-  ASSERT_TRUE(table->Equals(*concatenated));
-
-  ASSERT_TRUE(table->Equals(*r3));
-  ASSERT_TRUE(r2->Equals(*r4));
-  ASSERT_OK(ConcatenateTables({r1, r4}, &concatenated));
-  ASSERT_TRUE(table->Equals(*concatenated));
-}
-
-TEST(TestArrowReadWrite, GetRecordBatchReader) {
-  const int num_columns = 20;
-  const int num_rows = 1000;
-
-  std::shared_ptr<Table> table;
-  ASSERT_NO_FATAL_FAILURE(MakeDoubleTable(num_columns, num_rows, 1, &table));
-
-  std::shared_ptr<Buffer> buffer;
-  ASSERT_NO_FATAL_FAILURE(WriteTableToBuffer(table, num_rows / 2,
-                                             default_arrow_writer_properties(), &buffer));
-
-  std::unique_ptr<FileReader> reader;
-  ASSERT_OK_NO_THROW(OpenFile(std::make_shared<BufferReader>(buffer),
-                              ::arrow::default_memory_pool(),
-                              ::parquet::default_reader_properties(), nullptr, &reader));
-
-  std::shared_ptr<::arrow::RecordBatchReader> rb_reader;
-  ASSERT_OK_NO_THROW(reader->GetRecordBatchReader({0, 1}, &rb_reader));
-
-  std::shared_ptr<::arrow::RecordBatch> batch;
-
-  ASSERT_OK(rb_reader->ReadNext(&batch));
-  ASSERT_EQ(500, batch->num_rows());
-  ASSERT_EQ(20, batch->num_columns());
-
-  ASSERT_OK(rb_reader->ReadNext(&batch));
-  ASSERT_EQ(500, batch->num_rows());
-  ASSERT_EQ(20, batch->num_columns());
-
-  ASSERT_OK(rb_reader->ReadNext(&batch));
-  ASSERT_EQ(nullptr, batch);
-}
-
-TEST(TestArrowReadWrite, ScanContents) {
-  const int num_columns = 20;
-  const int num_rows = 1000;
-
-  std::shared_ptr<Table> table;
-  ASSERT_NO_FATAL_FAILURE(MakeDoubleTable(num_columns, num_rows, 1, &table));
-
-  std::shared_ptr<Buffer> buffer;
-  ASSERT_NO_FATAL_FAILURE(WriteTableToBuffer(table, num_rows / 2,
-                                             default_arrow_writer_properties(), &buffer));
-
-  std::unique_ptr<FileReader> reader;
-  ASSERT_OK_NO_THROW(OpenFile(std::make_shared<BufferReader>(buffer),
-                              ::arrow::default_memory_pool(),
-                              ::parquet::default_reader_properties(), nullptr, &reader));
-
-  int64_t num_rows_returned = 0;
-  ASSERT_OK_NO_THROW(reader->ScanContents({}, 256, &num_rows_returned));
-  ASSERT_EQ(num_rows, num_rows_returned);
-
-  ASSERT_OK_NO_THROW(reader->ScanContents({0, 1, 2}, 256, &num_rows_returned));
-  ASSERT_EQ(num_rows, num_rows_returned);
-}
-
-TEST(TestArrowReadWrite, ReadColumnSubset) {
-  const int num_columns = 20;
-  const int num_rows = 1000;
-  const bool use_threads = true;
-
-  std::shared_ptr<Table> table;
-  ASSERT_NO_FATAL_FAILURE(MakeDoubleTable(num_columns, num_rows, 1, &table));
-
-  std::shared_ptr<Table> result;
-  std::vector<int> column_subset = {0, 4, 8, 10};
-  ASSERT_NO_FATAL_FAILURE(
-      DoSimpleRoundtrip(table, use_threads, table->num_rows(), column_subset, &result));
-
-  std::vector<std::shared_ptr<::arrow::Column>> ex_columns;
-  std::vector<std::shared_ptr<::arrow::Field>> ex_fields;
-  for (int i : column_subset) {
-    ex_columns.push_back(table->column(i));
-    ex_fields.push_back(table->column(i)->field());
-  }
-
-  auto ex_schema = ::arrow::schema(ex_fields);
-  auto expected = Table::Make(ex_schema, ex_columns);
-  ASSERT_NO_FATAL_FAILURE(::arrow::AssertTablesEqual(*expected, *result));
-}
-
-TEST(TestArrowReadWrite, ListLargeRecords) {
-  // PARQUET-1308: This test passed on Linux when num_rows was smaller
-  const int num_rows = 2000;
-
-  std::shared_ptr<Array> list_array;
-  std::shared_ptr<::DataType> list_type;
-
-  MakeListArray(num_rows, 20, &list_type, &list_array);
-
-  auto schema = ::arrow::schema({::arrow::field("a", list_type)});
-
-  std::shared_ptr<Table> table = Table::Make(schema, {list_array});
-
-  std::shared_ptr<Buffer> buffer;
-  ASSERT_NO_FATAL_FAILURE(
-      WriteTableToBuffer(table, 100, default_arrow_writer_properties(), &buffer));
-
-  std::unique_ptr<FileReader> reader;
-  ASSERT_OK_NO_THROW(OpenFile(std::make_shared<BufferReader>(buffer),
-                              ::arrow::default_memory_pool(),
-                              ::parquet::default_reader_properties(), nullptr, &reader));
-
-  // Read everything
-  std::shared_ptr<Table> result;
-  ASSERT_OK_NO_THROW(reader->ReadTable(&result));
-  ASSERT_NO_FATAL_FAILURE(::arrow::AssertTablesEqual(*table, *result));
-
-  // Read chunked
-  ASSERT_OK_NO_THROW(OpenFile(std::make_shared<BufferReader>(buffer),
-                              ::arrow::default_memory_pool(),
-                              ::parquet::default_reader_properties(), nullptr, &reader));
-
-  std::unique_ptr<ColumnReader> col_reader;
-  ASSERT_OK(reader->GetColumn(0, &col_reader));
-
-  std::vector<std::shared_ptr<Array>> pieces;
-  for (int i = 0; i < num_rows; ++i) {
-    std::shared_ptr<Array> piece;
-    ASSERT_OK(col_reader->NextBatch(1, &piece));
-    ASSERT_EQ(1, piece->length());
-    pieces.push_back(piece);
-  }
-  auto chunked = std::make_shared<::arrow::ChunkedArray>(pieces);
-
-  auto chunked_col =
-      std::make_shared<::arrow::Column>(table->schema()->field(0), chunked);
-  std::vector<std::shared_ptr<::arrow::Column>> columns = {chunked_col};
-  auto chunked_table = Table::Make(table->schema(), columns);
-
-  ASSERT_TRUE(table->Equals(*chunked_table));
-}
-
-typedef std::function<void(int, std::shared_ptr<::DataType>*, std::shared_ptr<Array>*)>
-    ArrayFactory;
-
-template <typename ArrowType>
-struct GenerateArrayFunctor {
-  explicit GenerateArrayFunctor(double pct_null = 0.1) : pct_null(pct_null) {}
-
-  void operator()(int length, std::shared_ptr<::DataType>* type,
-                  std::shared_ptr<Array>* array) {
-    using T = typename ArrowType::c_type;
-
-    // TODO(wesm): generate things other than integers
-    std::vector<T> draws;
-    randint(length, 0, 100, &draws);
-
-    std::vector<bool> is_valid;
-    random_is_valid(length, this->pct_null, &is_valid);
-
-    *type = ::arrow::TypeTraits<ArrowType>::type_singleton();
-    ::arrow::ArrayFromVector<ArrowType, T>(*type, is_valid, draws, array);
-  }
-
-  double pct_null;
-};
-
-typedef std::function<void(int, std::shared_ptr<::DataType>*, std::shared_ptr<Array>*)>
-    ArrayFactory;
-
-auto GenerateInt32 = [](int length, std::shared_ptr<::DataType>* type,
-                        std::shared_ptr<Array>* array) {
-  GenerateArrayFunctor<::arrow::Int32Type> func;
-  func(length, type, array);
-};
-
-auto GenerateList = [](int length, std::shared_ptr<::DataType>* type,
-                       std::shared_ptr<Array>* array) {
-  MakeListArray(length, 100, type, array);
-};
-
-TEST(TestArrowReadWrite, TableWithChunkedColumns) {
-  std::vector<ArrayFactory> functions = {GenerateInt32, GenerateList};
-
-  std::vector<int> chunk_sizes = {2, 4, 10, 2};
-  const int64_t total_length = 18;
-
-  for (const auto& datagen_func : functions) {
-    ::arrow::ArrayVector arrays;
-    std::shared_ptr<Array> arr;
-    std::shared_ptr<::DataType> type;
-    datagen_func(total_length, &type, &arr);
-
-    int64_t offset = 0;
-    for (int chunk_size : chunk_sizes) {
-      arrays.push_back(arr->Slice(offset, chunk_size));
-      offset += chunk_size;
-    }
-
-    auto field = ::arrow::field("fname", type);
-    auto schema = ::arrow::schema({field});
-    auto col = std::make_shared<::arrow::Column>(field, arrays);
-    auto table = Table::Make(schema, {col});
-
-    ASSERT_NO_FATAL_FAILURE(CheckSimpleRoundtrip(table, 2));
-    ASSERT_NO_FATAL_FAILURE(CheckSimpleRoundtrip(table, 3));
-    ASSERT_NO_FATAL_FAILURE(CheckSimpleRoundtrip(table, 10));
-  }
-}
-
-TEST(TestArrowReadWrite, TableWithDuplicateColumns) {
-  // See ARROW-1974
-  using ::arrow::ArrayFromVector;
-
-  auto f0 = field("duplicate", ::arrow::int8());
-  auto f1 = field("duplicate", ::arrow::int16());
-  auto schema = ::arrow::schema({f0, f1});
-
-  std::vector<int8_t> a0_values = {1, 2, 3};
-  std::vector<int16_t> a1_values = {14, 15, 16};
-
-  std::shared_ptr<Array> a0, a1;
-
-  ArrayFromVector<::arrow::Int8Type, int8_t>(a0_values, &a0);
-  ArrayFromVector<::arrow::Int16Type, int16_t>(a1_values, &a1);
-
-  auto table = Table::Make(schema, {std::make_shared<Column>(f0->name(), a0),
-                                    std::make_shared<Column>(f1->name(), a1)});
-  ASSERT_NO_FATAL_FAILURE(CheckSimpleRoundtrip(table, table->num_rows()));
-}
-
-TEST(TestArrowReadWrite, DictionaryColumnChunkedWrite) {
-  // This is a regression test for this:
-  //
-  // https://issues.apache.org/jira/browse/ARROW-1938
-  //
-  // As of the writing of this test, columns of type
-  // dictionary are written as their raw/expanded values.
-  // The regression was that the whole column was being
-  // written for each chunk.
-  using ::arrow::ArrayFromVector;
-
-  std::vector<std::string> values = {"first", "second", "third"};
-  auto type = ::arrow::utf8();
-  std::shared_ptr<Array> dict_values;
-  ArrayFromVector<::arrow::StringType, std::string>(values, &dict_values);
-
-  auto dict_type = ::arrow::dictionary(::arrow::int32(), dict_values);
-  auto f0 = field("dictionary", dict_type);
-  std::vector<std::shared_ptr<::arrow::Field>> fields;
-  fields.emplace_back(f0);
-  auto schema = ::arrow::schema(fields);
-
-  std::shared_ptr<Array> f0_values, f1_values;
-  ArrayFromVector<::arrow::Int32Type, int32_t>({0, 1, 0, 2, 1}, &f0_values);
-  ArrayFromVector<::arrow::Int32Type, int32_t>({2, 0, 1, 0, 2}, &f1_values);
-  ::arrow::ArrayVector dict_arrays = {
-      std::make_shared<::arrow::DictionaryArray>(dict_type, f0_values),
-      std::make_shared<::arrow::DictionaryArray>(dict_type, f1_values)};
-
-  std::vector<std::shared_ptr<::arrow::Column>> columns;
-  auto column = MakeColumn("column", dict_arrays, false);
-  columns.emplace_back(column);
-
-  auto table = Table::Make(schema, columns);
-
-  std::shared_ptr<Table> result;
-  DoSimpleRoundtrip(table, 1,
-                    // Just need to make sure that we make
-                    // a chunk size that is smaller than the
-                    // total number of values
-                    2, {}, &result);
-
-  std::vector<std::string> expected_values = {"first",  "second", "first", "third",
-                                              "second", "third",  "first", "second",
-                                              "first",  "third"};
-  columns.clear();
-
-  std::shared_ptr<Array> expected_array;
-  ArrayFromVector<::arrow::StringType, std::string>(expected_values, &expected_array);
-
-  // The column name gets changed on output to the name of the
-  // field, and it also turns into a nullable column
-  columns.emplace_back(MakeColumn("dictionary", expected_array, true));
-
-  fields.clear();
-  fields.emplace_back(::arrow::field("dictionary", ::arrow::utf8()));
-  schema = ::arrow::schema(fields);
-
-  auto expected_table = Table::Make(schema, columns);
-
-  ::arrow::AssertTablesEqual(*expected_table, *result, false);
-}
-
-TEST(TestArrowWrite, CheckChunkSize) {
-  const int num_columns = 2;
-  const int num_rows = 128;
-  const int64_t chunk_size = 0;  // note the chunk_size is 0
-  std::shared_ptr<Table> table;
-  ASSERT_NO_FATAL_FAILURE(MakeDoubleTable(num_columns, num_rows, 1, &table));
-
-  auto sink = std::make_shared<InMemoryOutputStream>();
-
-  ASSERT_RAISES(Invalid,
-                WriteTable(*table, ::arrow::default_memory_pool(), sink, chunk_size));
-}
-
-class TestNestedSchemaRead : public ::testing::TestWithParam<Repetition::type> {
- protected:
-  // make it *3 to make it easily divisible by 3
-  const int NUM_SIMPLE_TEST_ROWS = SMALL_SIZE * 3;
-  std::shared_ptr<::arrow::Int32Array> values_array_ = nullptr;
-
-  void InitReader() {
-    std::shared_ptr<Buffer> buffer = nested_parquet_->GetBuffer();
-    ASSERT_OK_NO_THROW(
-        OpenFile(std::make_shared<BufferReader>(buffer), ::arrow::default_memory_pool(),
-                 ::parquet::default_reader_properties(), nullptr, &reader_));
-  }
-
-  void InitNewParquetFile(const std::shared_ptr<GroupNode>& schema, int num_rows) {
-    nested_parquet_ = std::make_shared<InMemoryOutputStream>();
-
-    writer_ = parquet::ParquetFileWriter::Open(nested_parquet_, schema,
-                                               default_writer_properties());
-    row_group_writer_ = writer_->AppendRowGroup();
-  }
-
-  void FinalizeParquetFile() {
-    row_group_writer_->Close();
-    writer_->Close();
-  }
-
-  void MakeValues(int num_rows) {
-    std::shared_ptr<Array> arr;
-    ASSERT_OK(NullableArray<::arrow::Int32Type>(num_rows, 0, kDefaultSeed, &arr));
-    values_array_ = std::dynamic_pointer_cast<::arrow::Int32Array>(arr);
-  }
-
-  void WriteColumnData(size_t num_rows, int16_t* def_levels, int16_t* rep_levels,
-                       int32_t* values) {
-    auto typed_writer =
-        static_cast<TypedColumnWriter<Int32Type>*>(row_group_writer_->NextColumn());
-    typed_writer->WriteBatch(num_rows, def_levels, rep_levels, values);
-  }
-
-  void ValidateArray(const Array& array, size_t expected_nulls) {
-    ASSERT_EQ(array.length(), values_array_->length());
-    ASSERT_EQ(array.null_count(), expected_nulls);
-    // Also independently count the nulls
-    auto local_null_count = 0;
-    for (int i = 0; i < array.length(); i++) {
-      if (array.IsNull(i)) {
-        local_null_count++;
-      }
-    }
-    ASSERT_EQ(local_null_count, expected_nulls);
-  }
-
-  void ValidateColumnArray(const ::arrow::Int32Array& array, size_t expected_nulls) {
-    ValidateArray(array, expected_nulls);
-    int j = 0;
-    for (int i = 0; i < values_array_->length(); i++) {
-      if (array.IsNull(i)) {
-        continue;
-      }
-      ASSERT_EQ(array.Value(i), values_array_->Value(j));
-      j++;
-    }
-  }
-
-  void ValidateTableArrayTypes(const Table& table) {
-    for (int i = 0; i < table.num_columns(); i++) {
-      const std::shared_ptr<::arrow::Field> schema_field = table.schema()->field(i);
-      const std::shared_ptr<Column> column = table.column(i);
-      // Compare with the column field
-      ASSERT_TRUE(schema_field->Equals(column->field()));
-      // Compare with the array type
-      ASSERT_TRUE(schema_field->type()->Equals(column->data()->chunk(0)->type()));
-    }
-  }
-
-  // A parquet with a simple nested schema
-  void CreateSimpleNestedParquet(Repetition::type struct_repetition) {
-    std::vector<NodePtr> parquet_fields;
-    // TODO(itaiin): We are using parquet low-level file api to create the nested parquet
-    // this needs to change when a nested writes are implemented
-
-    // create the schema:
-    // <struct_repetition> group group1 {
-    //   required int32 leaf1;
-    //   optional int32 leaf2;
-    // }
-    // required int32 leaf3;
-
-    parquet_fields.push_back(GroupNode::Make(
-        "group1", struct_repetition,
-        {PrimitiveNode::Make("leaf1", Repetition::REQUIRED, ParquetType::INT32),
-         PrimitiveNode::Make("leaf2", Repetition::OPTIONAL, ParquetType::INT32)}));
-    parquet_fields.push_back(
-        PrimitiveNode::Make("leaf3", Repetition::REQUIRED, ParquetType::INT32));
-
-    auto schema_node = GroupNode::Make("schema", Repetition::REQUIRED, parquet_fields);
-
-    // Create definition levels for the different columns that contain interleaved
-    // nulls and values at all nesting levels
-
-    //  definition levels for optional fields
-    std::vector<int16_t> leaf1_def_levels(NUM_SIMPLE_TEST_ROWS);
-    std::vector<int16_t> leaf2_def_levels(NUM_SIMPLE_TEST_ROWS);
-    std::vector<int16_t> leaf3_def_levels(NUM_SIMPLE_TEST_ROWS);
-    for (int i = 0; i < NUM_SIMPLE_TEST_ROWS; i++) {
-      // leaf1 is required within the optional group1, so it is only null
-      // when the group is null
-      leaf1_def_levels[i] = (i % 3 == 0) ? 0 : 1;
-      // leaf2 is optional, can be null in the primitive (def-level 1) or
-      // struct level (def-level 0)
-      leaf2_def_levels[i] = static_cast<int16_t>(i % 3);
-      // leaf3 is required
-      leaf3_def_levels[i] = 0;
-    }
-
-    std::vector<int16_t> rep_levels(NUM_SIMPLE_TEST_ROWS, 0);
-
-    // Produce values for the columns
-    MakeValues(NUM_SIMPLE_TEST_ROWS);
-    int32_t* values = reinterpret_cast<int32_t*>(values_array_->values()->mutable_data());
-
-    // Create the actual parquet file
-    InitNewParquetFile(std::static_pointer_cast<GroupNode>(schema_node),
-                       NUM_SIMPLE_TEST_ROWS);
-
-    // leaf1 column
-    WriteColumnData(NUM_SIMPLE_TEST_ROWS, leaf1_def_levels.data(), rep_levels.data(),
-                    values);
-    // leaf2 column
-    WriteColumnData(NUM_SIMPLE_TEST_ROWS, leaf2_def_levels.data(), rep_levels.data(),
-                    values);
-    // leaf3 column
-    WriteColumnData(NUM_SIMPLE_TEST_ROWS, leaf3_def_levels.data(), rep_levels.data(),
-                    values);
-
-    FinalizeParquetFile();
-    InitReader();
-  }
-
-  NodePtr CreateSingleTypedNestedGroup(int index, int depth, int num_children,
-                                       Repetition::type node_repetition,
-                                       ParquetType::type leaf_type) {
-    std::vector<NodePtr> children;
-
-    for (int i = 0; i < num_children; i++) {
-      if (depth <= 1) {
-        children.push_back(PrimitiveNode::Make("leaf", node_repetition, leaf_type));
-      } else {
-        children.push_back(CreateSingleTypedNestedGroup(i, depth - 1, num_children,
-                                                        node_repetition, leaf_type));
-      }
-    }
-
-    std::stringstream ss;
-    ss << "group-" << depth << "-" << index;
-    return NodePtr(GroupNode::Make(ss.str(), node_repetition, children));
-  }
-
-  // A deeply nested schema
-  void CreateMultiLevelNestedParquet(int num_trees, int tree_depth, int num_children,
-                                     int num_rows, Repetition::type node_repetition) {
-    // Create the schema
-    std::vector<NodePtr> parquet_fields;
-    for (int i = 0; i < num_trees; i++) {
-      parquet_fields.push_back(CreateSingleTypedNestedGroup(
-          i, tree_depth, num_children, node_repetition, ParquetType::INT32));
-    }
-    auto schema_node = GroupNode::Make("schema", Repetition::REQUIRED, parquet_fields);
-
-    int num_columns = num_trees * static_cast<int>((std::pow(num_children, tree_depth)));
-
-    std::vector<int16_t> def_levels;
-    std::vector<int16_t> rep_levels;
-
-    int num_levels = 0;
-    while (num_levels < num_rows) {
-      if (node_repetition == Repetition::REQUIRED) {
-        def_levels.push_back(0);  // all are required
-      } else {
-        int16_t level = static_cast<int16_t>(num_levels % (tree_depth + 2));
-        def_levels.push_back(level);  // all are optional
-      }
-      rep_levels.push_back(0);  // none is repeated
-      ++num_levels;
-    }
-
-    // Produce values for the columns
-    MakeValues(num_rows);
-    int32_t* values = reinterpret_cast<int32_t*>(values_array_->values()->mutable_data());
-
-    // Create the actual parquet file
-    InitNewParquetFile(std::static_pointer_cast<GroupNode>(schema_node), num_rows);
-
-    for (int i = 0; i < num_columns; i++) {
-      WriteColumnData(num_rows, def_levels.data(), rep_levels.data(), values);
-    }
-    FinalizeParquetFile();
-    InitReader();
-  }
-
-  class DeepParquetTestVisitor : public ArrayVisitor {
-   public:
-    DeepParquetTestVisitor(Repetition::type node_repetition,
-                           std::shared_ptr<::arrow::Int32Array> expected)
-        : node_repetition_(node_repetition), expected_(expected) {}
-
-    Status Validate(std::shared_ptr<Array> tree) { return tree->Accept(this); }
-
-    virtual Status Visit(const ::arrow::Int32Array& array) {
-      if (node_repetition_ == Repetition::REQUIRED) {
-        if (!array.Equals(expected_)) {
-          return Status::Invalid("leaf array data mismatch");
-        }
-      } else if (node_repetition_ == Repetition::OPTIONAL) {
-        if (array.length() != expected_->length()) {
-          return Status::Invalid("Bad leaf array length");
-        }
-        // expect only 1 value every `depth` row
-        if (array.null_count() != SMALL_SIZE) {
-          return Status::Invalid("Unexpected null count");
-        }
-      } else {
-        return Status::NotImplemented("Unsupported repetition");
-      }
-      return Status::OK();
-    }
-
-    virtual Status Visit(const ::arrow::StructArray& array) {
-      for (int32_t i = 0; i < array.num_fields(); ++i) {
-        auto child = array.field(i);
-        if (node_repetition_ == Repetition::REQUIRED) {
-          RETURN_NOT_OK(child->Accept(this));
-        } else if (node_repetition_ == Repetition::OPTIONAL) {
-          // Null count Must be a multiple of SMALL_SIZE
-          if (array.null_count() % SMALL_SIZE != 0) {
-            return Status::Invalid("Unexpected struct null count");
-          }
-        } else {
-          return Status::NotImplemented("Unsupported repetition");
-        }
-      }
-      return Status::OK();
-    }
-
-   private:
-    Repetition::type node_repetition_;
-    std::shared_ptr<::arrow::Int32Array> expected_;
-  };
-
-  std::shared_ptr<InMemoryOutputStream> nested_parquet_;
-  std::unique_ptr<FileReader> reader_;
-  std::unique_ptr<ParquetFileWriter> writer_;
-  RowGroupWriter* row_group_writer_;
-};
-
-TEST_F(TestNestedSchemaRead, ReadIntoTableFull) {
-  ASSERT_NO_FATAL_FAILURE(CreateSimpleNestedParquet(Repetition::OPTIONAL));
-
-  std::shared_ptr<Table> table;
-  ASSERT_OK_NO_THROW(reader_->ReadTable(&table));
-  ASSERT_EQ(table->num_rows(), NUM_SIMPLE_TEST_ROWS);
-  ASSERT_EQ(table->num_columns(), 2);
-  ASSERT_EQ(table->schema()->field(0)->type()->num_children(), 2);
-  ASSERT_NO_FATAL_FAILURE(ValidateTableArrayTypes(*table));
-
-  auto struct_field_array =
-      std::static_pointer_cast<::arrow::StructArray>(table->column(0)->data()->chunk(0));
-  auto leaf1_array =
-      std::static_pointer_cast<::arrow::Int32Array>(struct_field_array->field(0));
-  auto leaf2_array =
-      std::static_pointer_cast<::arrow::Int32Array>(struct_field_array->field(1));
-  auto leaf3_array =
-      std::static_pointer_cast<::arrow::Int32Array>(table->column(1)->data()->chunk(0));
-
-  // validate struct and leaf arrays
-
-  // validate struct array
-  ASSERT_NO_FATAL_FAILURE(ValidateArray(*struct_field_array, NUM_SIMPLE_TEST_ROWS / 3));
-  // validate leaf1
-  ASSERT_NO_FATAL_FAILURE(ValidateColumnArray(*leaf1_array, NUM_SIMPLE_TEST_ROWS / 3));
-  // validate leaf2
-  ASSERT_NO_FATAL_FAILURE(
-      ValidateColumnArray(*leaf2_array, NUM_SIMPLE_TEST_ROWS * 2 / 3));
-  // validate leaf3
-  ASSERT_NO_FATAL_FAILURE(ValidateColumnArray(*leaf3_array, 0));
-}
-
-TEST_F(TestNestedSchemaRead, ReadTablePartial) {
-  ASSERT_NO_FATAL_FAILURE(CreateSimpleNestedParquet(Repetition::OPTIONAL));
-  std::shared_ptr<Table> table;
-
-  // columns: {group1.leaf1, leaf3}
-  ASSERT_OK_NO_THROW(reader_->ReadTable({0, 2}, &table));
-  ASSERT_EQ(table->num_rows(), NUM_SIMPLE_TEST_ROWS);
-  ASSERT_EQ(table->num_columns(), 2);
-  ASSERT_EQ(table->schema()->field(0)->name(), "group1");
-  ASSERT_EQ(table->schema()->field(1)->name(), "leaf3");
-  ASSERT_EQ(table->schema()->field(0)->type()->num_children(), 1);
-  ASSERT_NO_FATAL_FAILURE(ValidateTableArrayTypes(*table));
-
-  // columns: {group1.leaf1, group1.leaf2}
-  ASSERT_OK_NO_THROW(reader_->ReadTable({0, 1}, &table));
-  ASSERT_EQ(table->num_rows(), NUM_SIMPLE_TEST_ROWS);
-  ASSERT_EQ(table->num_columns(), 1);
-  ASSERT_EQ(table->schema()->field(0)->name(), "group1");
-  ASSERT_EQ(table->schema()->field(0)->type()->num_children(), 2);
-  ASSERT_NO_FATAL_FAILURE(ValidateTableArrayTypes(*table));
-
-  // columns: {leaf3}
-  ASSERT_OK_NO_THROW(reader_->ReadTable({2}, &table));
-  ASSERT_EQ(table->num_rows(), NUM_SIMPLE_TEST_ROWS);
-  ASSERT_EQ(table->num_columns(), 1);
-  ASSERT_EQ(table->schema()->field(0)->name(), "leaf3");
-  ASSERT_EQ(table->schema()->field(0)->type()->num_children(), 0);
-  ASSERT_NO_FATAL_FAILURE(ValidateTableArrayTypes(*table));
-
-  // Test with different ordering
-  ASSERT_OK_NO_THROW(reader_->ReadTable({2, 0}, &table));
-  ASSERT_EQ(table->num_rows(), NUM_SIMPLE_TEST_ROWS);
-  ASSERT_EQ(table->num_columns(), 2);
-  ASSERT_EQ(table->schema()->field(0)->name(), "leaf3");
-  ASSERT_EQ(table->schema()->field(1)->name(), "group1");
-  ASSERT_EQ(table->schema()->field(1)->type()->num_children(), 1);
-  ASSERT_NO_FATAL_FAILURE(ValidateTableArrayTypes(*table));
-}
-
-TEST_F(TestNestedSchemaRead, StructAndListTogetherUnsupported) {
-  ASSERT_NO_FATAL_FAILURE(CreateSimpleNestedParquet(Repetition::REPEATED));
-  std::shared_ptr<Table> table;
-  ASSERT_RAISES(NotImplemented, reader_->ReadTable(&table));
-}
-
-TEST_P(TestNestedSchemaRead, DeepNestedSchemaRead) {
-#ifdef PARQUET_VALGRIND
-  const int num_trees = 3;
-  const int depth = 3;
-#else
-  const int num_trees = 10;
-  const int depth = 5;
-#endif
-  const int num_children = 3;
-  int num_rows = SMALL_SIZE * (depth + 2);
-  ASSERT_NO_FATAL_FAILURE(CreateMultiLevelNestedParquet(num_trees, depth, num_children,
-                                                        num_rows, GetParam()));
-  std::shared_ptr<Table> table;
-  ASSERT_OK_NO_THROW(reader_->ReadTable(&table));
-  ASSERT_EQ(table->num_columns(), num_trees);
-  ASSERT_EQ(table->num_rows(), num_rows);
-
-  DeepParquetTestVisitor visitor(GetParam(), values_array_);
-  for (int i = 0; i < table->num_columns(); i++) {
-    auto tree = table->column(i)->data()->chunk(0);
-    ASSERT_OK_NO_THROW(visitor.Validate(tree));
-  }
-}
-
-INSTANTIATE_TEST_CASE_P(Repetition_type, TestNestedSchemaRead,
-                        ::testing::Values(Repetition::REQUIRED, Repetition::OPTIONAL));
-
-TEST(TestImpalaConversion, NanosecondToImpala) {
-  // June 20, 2017 16:32:56 and 123456789 nanoseconds
-  int64_t nanoseconds = INT64_C(1497976376123456789);
-  Int96 expected = {{UINT32_C(632093973), UINT32_C(13871), UINT32_C(2457925)}};
-  Int96 calculated;
-  internal::NanosecondsToImpalaTimestamp(nanoseconds, &calculated);
-  ASSERT_EQ(expected, calculated);
-}
-
-TEST(TestArrowReaderAdHoc, Int96BadMemoryAccess) {
-  // PARQUET-995
-  std::string dir_string(test::get_data_dir());
-  std::stringstream ss;
-  ss << dir_string << "/"
-     << "alltypes_plain.parquet";
-  auto path = ss.str();
-
-  auto pool = ::arrow::default_memory_pool();
-
-  std::unique_ptr<FileReader> arrow_reader;
-  ASSERT_NO_THROW(
-      arrow_reader.reset(new FileReader(pool, ParquetFileReader::OpenFile(path, false))));
-  std::shared_ptr<::arrow::Table> table;
-  ASSERT_OK_NO_THROW(arrow_reader->ReadTable(&table));
-}
-
-class TestArrowReaderAdHocSpark
-    : public ::testing::TestWithParam<
-          std::tuple<std::string, std::shared_ptr<::DataType>>> {};
-
-TEST_P(TestArrowReaderAdHocSpark, ReadDecimals) {
-  std::string path(test::get_data_dir());
-
-  std::string filename;
-  std::shared_ptr<::DataType> decimal_type;
-  std::tie(filename, decimal_type) = GetParam();
-
-  path += "/" + filename;
-  ASSERT_GT(path.size(), 0);
-
-  auto pool = ::arrow::default_memory_pool();
-
-  std::unique_ptr<FileReader> arrow_reader;
-  ASSERT_NO_THROW(
-      arrow_reader.reset(new FileReader(pool, ParquetFileReader::OpenFile(path, false))));
-  std::shared_ptr<::arrow::Table> table;
-  ASSERT_OK_NO_THROW(arrow_reader->ReadTable(&table));
-
-  ASSERT_EQ(1, table->num_columns());
-
-  constexpr int32_t expected_length = 24;
-
-  auto value_column = table->column(0);
-  ASSERT_EQ(expected_length, value_column->length());
-
-  auto raw_array = value_column->data();
-  ASSERT_EQ(1, raw_array->num_chunks());
-
-  auto chunk = raw_array->chunk(0);
-
-  std::shared_ptr<Array> expected_array;
-
-  ::arrow::Decimal128Builder builder(decimal_type, pool);
-
-  for (int32_t i = 0; i < expected_length; ++i) {
-    ::arrow::Decimal128 value((i + 1) * 100);
-    ASSERT_OK(builder.Append(value));
-  }
-  ASSERT_OK(builder.Finish(&expected_array));
-
-  internal::AssertArraysEqual(*expected_array, *chunk);
-}
-
-INSTANTIATE_TEST_CASE_P(
-    ReadDecimals, TestArrowReaderAdHocSpark,
-    ::testing::Values(
-        std::make_tuple("int32_decimal.parquet", ::arrow::decimal(4, 2)),
-        std::make_tuple("int64_decimal.parquet", ::arrow::decimal(10, 2)),
-        std::make_tuple("fixed_length_decimal.parquet", ::arrow::decimal(25, 2)),
-        std::make_tuple("fixed_length_decimal_legacy.parquet", ::arrow::decimal(13, 2))));
-
-}  // namespace arrow
-
-}  // namespace parquet
diff --git a/src/parquet/arrow/arrow-schema-test.cc b/src/parquet/arrow/arrow-schema-test.cc
deleted file mode 100644
index cb2b850..0000000
--- a/src/parquet/arrow/arrow-schema-test.cc
+++ /dev/null
@@ -1,852 +0,0 @@
-// 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.
-
-#include <memory>
-#include <vector>
-
-#include "gtest/gtest.h"
-
-#include "parquet/arrow/schema.h"
-
-#include "arrow/api.h"
-#include "arrow/test-util.h"
-
-using arrow::ArrayFromVector;
-using arrow::Field;
-using arrow::TimeUnit;
-
-using ParquetType = parquet::Type;
-using parquet::LogicalType;
-using parquet::Repetition;
-using parquet::schema::GroupNode;
-using parquet::schema::NodePtr;
-using parquet::schema::PrimitiveNode;
-
-namespace parquet {
-
-namespace arrow {
-
-const auto BOOL = ::arrow::boolean();
-const auto UINT8 = ::arrow::uint8();
-const auto INT32 = ::arrow::int32();
-const auto INT64 = ::arrow::int64();
-const auto FLOAT = ::arrow::float32();
-const auto DOUBLE = ::arrow::float64();
-const auto UTF8 = ::arrow::utf8();
-const auto TIMESTAMP_MS = ::arrow::timestamp(TimeUnit::MILLI);
-const auto TIMESTAMP_US = ::arrow::timestamp(TimeUnit::MICRO);
-const auto TIMESTAMP_NS = ::arrow::timestamp(TimeUnit::NANO);
-const auto BINARY = ::arrow::binary();
-const auto DECIMAL_8_4 = std::make_shared<::arrow::Decimal128Type>(8, 4);
-
-class TestConvertParquetSchema : public ::testing::Test {
- public:
-  virtual void SetUp() {}
-
-  void CheckFlatSchema(const std::shared_ptr<::arrow::Schema>& expected_schema) {
-    ASSERT_EQ(expected_schema->num_fields(), result_schema_->num_fields());
-    for (int i = 0; i < expected_schema->num_fields(); ++i) {
-      auto lhs = result_schema_->field(i);
-      auto rhs = expected_schema->field(i);
-      EXPECT_TRUE(lhs->Equals(rhs))
-          << i << " " << lhs->ToString() << " != " << rhs->ToString();
-    }
-  }
-
-  ::arrow::Status ConvertSchema(const std::vector<NodePtr>& nodes) {
-    NodePtr schema = GroupNode::Make("schema", Repetition::REPEATED, nodes);
-    descr_.Init(schema);
-    return FromParquetSchema(&descr_, &result_schema_);
-  }
-
-  ::arrow::Status ConvertSchema(const std::vector<NodePtr>& nodes,
-                                const std::vector<int>& column_indices) {
-    NodePtr schema = GroupNode::Make("schema", Repetition::REPEATED, nodes);
-    descr_.Init(schema);
-    return FromParquetSchema(&descr_, column_indices, &result_schema_);
-  }
-
-  ::arrow::Status ConvertSchema(
-      const std::vector<NodePtr>& nodes,
-      const std::shared_ptr<const KeyValueMetadata>& key_value_metadata) {
-    NodePtr schema = GroupNode::Make("schema", Repetition::REPEATED, nodes);
-    descr_.Init(schema);
-    return FromParquetSchema(&descr_, {}, key_value_metadata, &result_schema_);
-  }
-
- protected:
-  SchemaDescriptor descr_;
-  std::shared_ptr<::arrow::Schema> result_schema_;
-};
-
-TEST_F(TestConvertParquetSchema, ParquetFlatPrimitives) {
-  std::vector<NodePtr> parquet_fields;
-  std::vector<std::shared_ptr<Field>> arrow_fields;
-
-  parquet_fields.push_back(
-      PrimitiveNode::Make("boolean", Repetition::REQUIRED, ParquetType::BOOLEAN));
-  arrow_fields.push_back(std::make_shared<Field>("boolean", BOOL, false));
-
-  parquet_fields.push_back(
-      PrimitiveNode::Make("int32", Repetition::REQUIRED, ParquetType::INT32));
-  arrow_fields.push_back(std::make_shared<Field>("int32", INT32, false));
-
-  parquet_fields.push_back(
-      PrimitiveNode::Make("int64", Repetition::REQUIRED, ParquetType::INT64));
-  arrow_fields.push_back(std::make_shared<Field>("int64", INT64, false));
-
-  parquet_fields.push_back(PrimitiveNode::Make("timestamp", Repetition::REQUIRED,
-                                               ParquetType::INT64,
-                                               LogicalType::TIMESTAMP_MILLIS));
-  arrow_fields.push_back(std::make_shared<Field>("timestamp", TIMESTAMP_MS, false));
-
-  parquet_fields.push_back(PrimitiveNode::Make("timestamp[us]", Repetition::REQUIRED,
-                                               ParquetType::INT64,
-                                               LogicalType::TIMESTAMP_MICROS));
-  arrow_fields.push_back(std::make_shared<Field>("timestamp[us]", TIMESTAMP_US, false));
-
-  parquet_fields.push_back(PrimitiveNode::Make("date", Repetition::REQUIRED,
-                                               ParquetType::INT32, LogicalType::DATE));
-  arrow_fields.push_back(std::make_shared<Field>("date", ::arrow::date32(), false));
-
-  parquet_fields.push_back(PrimitiveNode::Make(
-      "time32", Repetition::REQUIRED, ParquetType::INT32, LogicalType::TIME_MILLIS));
-  arrow_fields.push_back(
-      std::make_shared<Field>("time32", ::arrow::time32(TimeUnit::MILLI), false));
-
-  parquet_fields.push_back(PrimitiveNode::Make(
-      "time64", Repetition::REQUIRED, ParquetType::INT64, LogicalType::TIME_MICROS));
-  arrow_fields.push_back(
-      std::make_shared<Field>("time64", ::arrow::time64(TimeUnit::MICRO), false));
-
-  parquet_fields.push_back(
-      PrimitiveNode::Make("timestamp96", Repetition::REQUIRED, ParquetType::INT96));
-  arrow_fields.push_back(std::make_shared<Field>("timestamp96", TIMESTAMP_NS, false));
-
-  parquet_fields.push_back(
-      PrimitiveNode::Make("float", Repetition::OPTIONAL, ParquetType::FLOAT));
-  arrow_fields.push_back(std::make_shared<Field>("float", FLOAT));
-
-  parquet_fields.push_back(
-      PrimitiveNode::Make("double", Repetition::OPTIONAL, ParquetType::DOUBLE));
-  arrow_fields.push_back(std::make_shared<Field>("double", DOUBLE));
-
-  parquet_fields.push_back(
-      PrimitiveNode::Make("binary", Repetition::OPTIONAL, ParquetType::BYTE_ARRAY));
-  arrow_fields.push_back(std::make_shared<Field>("binary", BINARY));
-
-  parquet_fields.push_back(PrimitiveNode::Make(
-      "string", Repetition::OPTIONAL, ParquetType::BYTE_ARRAY, LogicalType::UTF8));
-  arrow_fields.push_back(std::make_shared<Field>("string", UTF8));
-
-  parquet_fields.push_back(PrimitiveNode::Make("flba-binary", Repetition::OPTIONAL,
-                                               ParquetType::FIXED_LEN_BYTE_ARRAY,
-                                               LogicalType::NONE, 12));
-  arrow_fields.push_back(
-      std::make_shared<Field>("flba-binary", ::arrow::fixed_size_binary(12)));
-
-  auto arrow_schema = std::make_shared<::arrow::Schema>(arrow_fields);
-  ASSERT_OK(ConvertSchema(parquet_fields));
-
-  ASSERT_NO_FATAL_FAILURE(CheckFlatSchema(arrow_schema));
-}
-
-TEST_F(TestConvertParquetSchema, DuplicateFieldNames) {
-  std::vector<NodePtr> parquet_fields;
-  std::vector<std::shared_ptr<Field>> arrow_fields;
-
-  parquet_fields.push_back(
-      PrimitiveNode::Make("xxx", Repetition::REQUIRED, ParquetType::BOOLEAN));
-  auto arrow_field1 = std::make_shared<Field>("xxx", BOOL, false);
-
-  parquet_fields.push_back(
-      PrimitiveNode::Make("xxx", Repetition::REQUIRED, ParquetType::INT32));
-  auto arrow_field2 = std::make_shared<Field>("xxx", INT32, false);
-
-  ASSERT_OK(ConvertSchema(parquet_fields));
-  arrow_fields = {arrow_field1, arrow_field2};
-  ASSERT_NO_FATAL_FAILURE(
-      CheckFlatSchema(std::make_shared<::arrow::Schema>(arrow_fields)));
-
-  ASSERT_OK(ConvertSchema(parquet_fields, std::vector<int>({0, 1})));
-  arrow_fields = {arrow_field1, arrow_field2};
-  ASSERT_NO_FATAL_FAILURE(
-      CheckFlatSchema(std::make_shared<::arrow::Schema>(arrow_fields)));
-
-  ASSERT_OK(ConvertSchema(parquet_fields, std::vector<int>({1, 0})));
-  arrow_fields = {arrow_field2, arrow_field1};
-  ASSERT_NO_FATAL_FAILURE(
-      CheckFlatSchema(std::make_shared<::arrow::Schema>(arrow_fields)));
-}
-
-TEST_F(TestConvertParquetSchema, ParquetKeyValueMetadata) {
-  std::vector<NodePtr> parquet_fields;
-  std::vector<std::shared_ptr<Field>> arrow_fields;
-
-  parquet_fields.push_back(
-      PrimitiveNode::Make("boolean", Repetition::REQUIRED, ParquetType::BOOLEAN));
-  arrow_fields.push_back(std::make_shared<Field>("boolean", BOOL, false));
-
-  parquet_fields.push_back(
-      PrimitiveNode::Make("int32", Repetition::REQUIRED, ParquetType::INT32));
-  arrow_fields.push_back(std::make_shared<Field>("int32", INT32, false));
-
-  auto key_value_metadata = std::make_shared<KeyValueMetadata>();
-  key_value_metadata->Append("foo", "bar");
-  key_value_metadata->Append("biz", "baz");
-  ASSERT_OK(ConvertSchema(parquet_fields, key_value_metadata));
-
-  auto arrow_metadata = result_schema_->metadata();
-  ASSERT_EQ("foo", arrow_metadata->key(0));
-  ASSERT_EQ("bar", arrow_metadata->value(0));
-  ASSERT_EQ("biz", arrow_metadata->key(1));
-  ASSERT_EQ("baz", arrow_metadata->value(1));
-}
-
-TEST_F(TestConvertParquetSchema, ParquetEmptyKeyValueMetadata) {
-  std::vector<NodePtr> parquet_fields;
-  std::vector<std::shared_ptr<Field>> arrow_fields;
-
-  parquet_fields.push_back(
-      PrimitiveNode::Make("int32", Repetition::REQUIRED, ParquetType::INT32));
-  arrow_fields.push_back(std::make_shared<Field>("int32", INT32, false));
-
-  std::shared_ptr<KeyValueMetadata> key_value_metadata = nullptr;
-  ASSERT_OK(ConvertSchema(parquet_fields, key_value_metadata));
-
-  auto arrow_metadata = result_schema_->metadata();
-  ASSERT_EQ(arrow_metadata, nullptr);
-}
-
-TEST_F(TestConvertParquetSchema, ParquetFlatDecimals) {
-  std::vector<NodePtr> parquet_fields;
-  std::vector<std::shared_ptr<Field>> arrow_fields;
-
-  parquet_fields.push_back(PrimitiveNode::Make("flba-decimal", Repetition::OPTIONAL,
-                                               ParquetType::FIXED_LEN_BYTE_ARRAY,
-                                               LogicalType::DECIMAL, 4, 8, 4));
-  arrow_fields.push_back(std::make_shared<Field>("flba-decimal", DECIMAL_8_4));
-
-  parquet_fields.push_back(PrimitiveNode::Make("binary-decimal", Repetition::OPTIONAL,
-                                               ParquetType::BYTE_ARRAY,
-                                               LogicalType::DECIMAL, -1, 8, 4));
-  arrow_fields.push_back(std::make_shared<Field>("binary-decimal", DECIMAL_8_4));
-
-  parquet_fields.push_back(PrimitiveNode::Make("int32-decimal", Repetition::OPTIONAL,
-                                               ParquetType::INT32, LogicalType::DECIMAL,
-                                               -1, 8, 4));
-  arrow_fields.push_back(std::make_shared<Field>("int32-decimal", DECIMAL_8_4));
-
-  parquet_fields.push_back(PrimitiveNode::Make("int64-decimal", Repetition::OPTIONAL,
-                                               ParquetType::INT64, LogicalType::DECIMAL,
-                                               -1, 8, 4));
-  arrow_fields.push_back(std::make_shared<Field>("int64-decimal", DECIMAL_8_4));
-
-  auto arrow_schema = std::make_shared<::arrow::Schema>(arrow_fields);
-  ASSERT_OK(ConvertSchema(parquet_fields));
-
-  ASSERT_NO_FATAL_FAILURE(CheckFlatSchema(arrow_schema));
-}
-
-TEST_F(TestConvertParquetSchema, ParquetLists) {
-  std::vector<NodePtr> parquet_fields;
-  std::vector<std::shared_ptr<Field>> arrow_fields;
-
-  // LIST encoding example taken from parquet-format/LogicalTypes.md
-
-  // // List<String> (list non-null, elements nullable)
-  // required group my_list (LIST) {
-  //   repeated group list {
-  //     optional binary element (UTF8);
-  //   }
-  // }
-  {
-    auto element = PrimitiveNode::Make("string", Repetition::OPTIONAL,
-                                       ParquetType::BYTE_ARRAY, LogicalType::UTF8);
-    auto list = GroupNode::Make("list", Repetition::REPEATED, {element});
-    parquet_fields.push_back(
-        GroupNode::Make("my_list", Repetition::REQUIRED, {list}, LogicalType::LIST));
-    auto arrow_element = std::make_shared<Field>("string", UTF8, true);
-    auto arrow_list = std::make_shared<::arrow::ListType>(arrow_element);
-    arrow_fields.push_back(std::make_shared<Field>("my_list", arrow_list, false));
-  }
-
-  // // List<String> (list nullable, elements non-null)
-  // optional group my_list (LIST) {
-  //   repeated group list {
-  //     required binary element (UTF8);
-  //   }
-  // }
-  {
-    auto element = PrimitiveNode::Make("string", Repetition::REQUIRED,
-                                       ParquetType::BYTE_ARRAY, LogicalType::UTF8);
-    auto list = GroupNode::Make("list", Repetition::REPEATED, {element});
-    parquet_fields.push_back(
-        GroupNode::Make("my_list", Repetition::OPTIONAL, {list}, LogicalType::LIST));
-    auto arrow_element = std::make_shared<Field>("string", UTF8, false);
-    auto arrow_list = std::make_shared<::arrow::ListType>(arrow_element);
-    arrow_fields.push_back(std::make_shared<Field>("my_list", arrow_list, true));
-  }
-
-  // Element types can be nested structures. For example, a list of lists:
-  //
-  // // List<List<Integer>>
-  // optional group array_of_arrays (LIST) {
-  //   repeated group list {
-  //     required group element (LIST) {
-  //       repeated group list {
-  //         required int32 element;
-  //       }
-  //     }
-  //   }
-  // }
-  {
-    auto inner_element =
-        PrimitiveNode::Make("int32", Repetition::REQUIRED, ParquetType::INT32);
-    auto inner_list = GroupNode::Make("list", Repetition::REPEATED, {inner_element});
-    auto element =
-        GroupNode::Make("element", Repetition::REQUIRED, {inner_list}, LogicalType::LIST);
-    auto list = GroupNode::Make("list", Repetition::REPEATED, {element});
-    parquet_fields.push_back(GroupNode::Make("array_of_arrays", Repetition::OPTIONAL,
-                                             {list}, LogicalType::LIST));
-    auto arrow_inner_element = std::make_shared<Field>("int32", INT32, false);
-    auto arrow_inner_list = std::make_shared<::arrow::ListType>(arrow_inner_element);
-    auto arrow_element = std::make_shared<Field>("element", arrow_inner_list, false);
-    auto arrow_list = std::make_shared<::arrow::ListType>(arrow_element);
-    arrow_fields.push_back(std::make_shared<Field>("array_of_arrays", arrow_list, true));
-  }
-
-  // // List<String> (list nullable, elements non-null)
-  // optional group my_list (LIST) {
-  //   repeated group element {
-  //     required binary str (UTF8);
-  //   };
-  // }
-  {
-    auto element = PrimitiveNode::Make("str", Repetition::REQUIRED,
-                                       ParquetType::BYTE_ARRAY, LogicalType::UTF8);
-    auto list = GroupNode::Make("element", Repetition::REPEATED, {element});
-    parquet_fields.push_back(
-        GroupNode::Make("my_list", Repetition::OPTIONAL, {list}, LogicalType::LIST));
-    auto arrow_element = std::make_shared<Field>("str", UTF8, false);
-    auto arrow_list = std::make_shared<::arrow::ListType>(arrow_element);
-    arrow_fields.push_back(std::make_shared<Field>("my_list", arrow_list, true));
-  }
-
-  // // List<Integer> (nullable list, non-null elements)
-  // optional group my_list (LIST) {
-  //   repeated int32 element;
-  // }
-  {
-    auto element =
-        PrimitiveNode::Make("element", Repetition::REPEATED, ParquetType::INT32);
-    parquet_fields.push_back(
-        GroupNode::Make("my_list", Repetition::OPTIONAL, {element}, LogicalType::LIST));
-    auto arrow_element = std::make_shared<Field>("element", INT32, false);
-    auto arrow_list = std::make_shared<::arrow::ListType>(arrow_element);
-    arrow_fields.push_back(std::make_shared<Field>("my_list", arrow_list, true));
-  }
-
-  // // List<Tuple<String, Integer>> (nullable list, non-null elements)
-  // optional group my_list (LIST) {
-  //   repeated group element {
-  //     required binary str (UTF8);
-  //     required int32 num;
-  //   };
-  // }
-  {
-    auto str_element = PrimitiveNode::Make("str", Repetition::REQUIRED,
-                                           ParquetType::BYTE_ARRAY, LogicalType::UTF8);
-    auto num_element =
-        PrimitiveNode::Make("num", Repetition::REQUIRED, ParquetType::INT32);
-    auto element =
-        GroupNode::Make("element", Repetition::REPEATED, {str_element, num_element});
-    parquet_fields.push_back(
-        GroupNode::Make("my_list", Repetition::OPTIONAL, {element}, LogicalType::LIST));
-    auto arrow_str = std::make_shared<Field>("str", UTF8, false);
-    auto arrow_num = std::make_shared<Field>("num", INT32, false);
-    std::vector<std::shared_ptr<Field>> fields({arrow_str, arrow_num});
-    auto arrow_struct = std::make_shared<::arrow::StructType>(fields);
-    auto arrow_element = std::make_shared<Field>("element", arrow_struct, false);
-    auto arrow_list = std::make_shared<::arrow::ListType>(arrow_element);
-    arrow_fields.push_back(std::make_shared<Field>("my_list", arrow_list, true));
-  }
-
-  // // List<OneTuple<String>> (nullable list, non-null elements)
-  // optional group my_list (LIST) {
-  //   repeated group array {
-  //     required binary str (UTF8);
-  //   };
-  // }
-  // Special case: group is named array
-  {
-    auto element = PrimitiveNode::Make("str", Repetition::REQUIRED,
-                                       ParquetType::BYTE_ARRAY, LogicalType::UTF8);
-    auto array = GroupNode::Make("array", Repetition::REPEATED, {element});
-    parquet_fields.push_back(
-        GroupNode::Make("my_list", Repetition::OPTIONAL, {array}, LogicalType::LIST));
-    auto arrow_str = std::make_shared<Field>("str", UTF8, false);
-    std::vector<std::shared_ptr<Field>> fields({arrow_str});
-    auto arrow_struct = std::make_shared<::arrow::StructType>(fields);
-    auto arrow_element = std::make_shared<Field>("array", arrow_struct, false);
-    auto arrow_list = std::make_shared<::arrow::ListType>(arrow_element);
-    arrow_fields.push_back(std::make_shared<Field>("my_list", arrow_list, true));
-  }
-
-  // // List<OneTuple<String>> (nullable list, non-null elements)
-  // optional group my_list (LIST) {
-  //   repeated group my_list_tuple {
-  //     required binary str (UTF8);
-  //   };
-  // }
-  // Special case: group named ends in _tuple
-  {
-    auto element = PrimitiveNode::Make("str", Repetition::REQUIRED,
-                                       ParquetType::BYTE_ARRAY, LogicalType::UTF8);
-    auto array = GroupNode::Make("my_list_tuple", Repetition::REPEATED, {element});
-    parquet_fields.push_back(
-        GroupNode::Make("my_list", Repetition::OPTIONAL, {array}, LogicalType::LIST));
-    auto arrow_str = std::make_shared<Field>("str", UTF8, false);
-    std::vector<std::shared_ptr<Field>> fields({arrow_str});
-    auto arrow_struct = std::make_shared<::arrow::StructType>(fields);
-    auto arrow_element = std::make_shared<Field>("my_list_tuple", arrow_struct, false);
-    auto arrow_list = std::make_shared<::arrow::ListType>(arrow_element);
-    arrow_fields.push_back(std::make_shared<Field>("my_list", arrow_list, true));
-  }
-
-  // One-level encoding: Only allows required lists with required cells
-  //   repeated value_type name
-  {
-    parquet_fields.push_back(
-        PrimitiveNode::Make("name", Repetition::REPEATED, ParquetType::INT32));
-    auto arrow_element = std::make_shared<Field>("name", INT32, false);
-    auto arrow_list = std::make_shared<::arrow::ListType>(arrow_element);
-    arrow_fields.push_back(std::make_shared<Field>("name", arrow_list, false));
-  }
-
-  auto arrow_schema = std::make_shared<::arrow::Schema>(arrow_fields);
-  ASSERT_OK(ConvertSchema(parquet_fields));
-
-  ASSERT_NO_FATAL_FAILURE(CheckFlatSchema(arrow_schema));
-}
-
-TEST_F(TestConvertParquetSchema, UnsupportedThings) {
-  std::vector<NodePtr> unsupported_nodes;
-
-  for (const NodePtr& node : unsupported_nodes) {
-    ASSERT_RAISES(NotImplemented, ConvertSchema({node}));
-  }
-}
-
-TEST_F(TestConvertParquetSchema, ParquetNestedSchema) {
-  std::vector<NodePtr> parquet_fields;
-  std::vector<std::shared_ptr<Field>> arrow_fields;
-
-  // required group group1 {
-  //   required bool leaf1;
-  //   required int32 leaf2;
-  // }
-  // required int64 leaf3;
-  {
-    parquet_fields.push_back(GroupNode::Make(
-        "group1", Repetition::REQUIRED,
-        {PrimitiveNode::Make("leaf1", Repetition::REQUIRED, ParquetType::BOOLEAN),
-         PrimitiveNode::Make("leaf2", Repetition::REQUIRED, ParquetType::INT32)}));
-    parquet_fields.push_back(
-        PrimitiveNode::Make("leaf3", Repetition::REQUIRED, ParquetType::INT64));
-
-    auto group1_fields = {std::make_shared<Field>("leaf1", BOOL, false),
-                          std::make_shared<Field>("leaf2", INT32, false)};
-    auto arrow_group1_type = std::make_shared<::arrow::StructType>(group1_fields);
-    arrow_fields.push_back(std::make_shared<Field>("group1", arrow_group1_type, false));
-    arrow_fields.push_back(std::make_shared<Field>("leaf3", INT64, false));
-  }
-
-  auto arrow_schema = std::make_shared<::arrow::Schema>(arrow_fields);
-  ASSERT_OK(ConvertSchema(parquet_fields));
-
-  ASSERT_NO_FATAL_FAILURE(CheckFlatSchema(arrow_schema));
-}
-
-TEST_F(TestConvertParquetSchema, ParquetNestedSchemaPartial) {
-  std::vector<NodePtr> parquet_fields;
-  std::vector<std::shared_ptr<Field>> arrow_fields;
-
-  // Full Parquet Schema:
-  // required group group1 {
-  //   required int64 leaf1;
-  //   required int64 leaf2;
-  // }
-  // required group group2 {
-  //   required int64 leaf3;
-  //   required int64 leaf4;
-  // }
-  // required int64 leaf5;
-  //
-  // Expected partial arrow schema (columns 0, 3, 4):
-  // required group group1 {
-  //   required int64 leaf1;
-  // }
-  // required group group2 {
-  //   required int64 leaf4;
-  // }
-  // required int64 leaf5;
-  {
-    parquet_fields.push_back(GroupNode::Make(
-        "group1", Repetition::REQUIRED,
-        {PrimitiveNode::Make("leaf1", Repetition::REQUIRED, ParquetType::INT64),
-         PrimitiveNode::Make("leaf2", Repetition::REQUIRED, ParquetType::INT64)}));
-    parquet_fields.push_back(GroupNode::Make(
-        "group2", Repetition::REQUIRED,
-        {PrimitiveNode::Make("leaf3", Repetition::REQUIRED, ParquetType::INT64),
-         PrimitiveNode::Make("leaf4", Repetition::REQUIRED, ParquetType::INT64)}));
-    parquet_fields.push_back(
-        PrimitiveNode::Make("leaf5", Repetition::REQUIRED, ParquetType::INT64));
-
-    auto group1_fields = {std::make_shared<Field>("leaf1", INT64, false)};
-    auto arrow_group1_type = std::make_shared<::arrow::StructType>(group1_fields);
-    auto group2_fields = {std::make_shared<Field>("leaf4", INT64, false)};
-    auto arrow_group2_type = std::make_shared<::arrow::StructType>(group2_fields);
-
-    arrow_fields.push_back(std::make_shared<Field>("group1", arrow_group1_type, false));
-    arrow_fields.push_back(std::make_shared<Field>("group2", arrow_group2_type, false));
-    arrow_fields.push_back(std::make_shared<Field>("leaf5", INT64, false));
-  }
-
-  auto arrow_schema = std::make_shared<::arrow::Schema>(arrow_fields);
-  ASSERT_OK(ConvertSchema(parquet_fields, std::vector<int>{0, 3, 4}));
-
-  ASSERT_NO_FATAL_FAILURE(CheckFlatSchema(arrow_schema));
-}
-
-TEST_F(TestConvertParquetSchema, ParquetNestedSchemaPartialOrdering) {
-  std::vector<NodePtr> parquet_fields;
-  std::vector<std::shared_ptr<Field>> arrow_fields;
-
-  // Full Parquet Schema:
-  // required group group1 {
-  //   required int64 leaf1;
-  //   required int64 leaf2;
-  // }
-  // required group group2 {
-  //   required int64 leaf3;
-  //   required int64 leaf4;
-  // }
-  // required int64 leaf5;
-  //
-  // Expected partial arrow schema (columns 3, 4, 0):
-  // required group group2 {
-  //   required int64 leaf4;
-  // }
-  // required int64 leaf5;
-  // required group group1 {
-  //   required int64 leaf1;
-  // }
-  {
-    parquet_fields.push_back(GroupNode::Make(
-        "group1", Repetition::REQUIRED,
-        {PrimitiveNode::Make("leaf1", Repetition::REQUIRED, ParquetType::INT64),
-         PrimitiveNode::Make("leaf2", Repetition::REQUIRED, ParquetType::INT64)}));
-    parquet_fields.push_back(GroupNode::Make(
-        "group2", Repetition::REQUIRED,
-        {PrimitiveNode::Make("leaf3", Repetition::REQUIRED, ParquetType::INT64),
-         PrimitiveNode::Make("leaf4", Repetition::REQUIRED, ParquetType::INT64)}));
-    parquet_fields.push_back(
-        PrimitiveNode::Make("leaf5", Repetition::REQUIRED, ParquetType::INT64));
-
-    auto group1_fields = {std::make_shared<Field>("leaf1", INT64, false)};
-    auto arrow_group1_type = std::make_shared<::arrow::StructType>(group1_fields);
-    auto group2_fields = {std::make_shared<Field>("leaf4", INT64, false)};
-    auto arrow_group2_type = std::make_shared<::arrow::StructType>(group2_fields);
-
-    arrow_fields.push_back(std::make_shared<Field>("group2", arrow_group2_type, false));
-    arrow_fields.push_back(std::make_shared<Field>("leaf5", INT64, false));
-    arrow_fields.push_back(std::make_shared<Field>("group1", arrow_group1_type, false));
-  }
-
-  auto arrow_schema = std::make_shared<::arrow::Schema>(arrow_fields);
-  ASSERT_OK(ConvertSchema(parquet_fields, std::vector<int>{3, 4, 0}));
-
-  ASSERT_NO_FATAL_FAILURE(CheckFlatSchema(arrow_schema));
-}
-TEST_F(TestConvertParquetSchema, ParquetRepeatedNestedSchema) {
-  std::vector<NodePtr> parquet_fields;
-  std::vector<std::shared_ptr<Field>> arrow_fields;
-  {
-    //   optional int32 leaf1;
-    //   repeated group outerGroup {
-    //     optional int32 leaf2;
-    //     repeated group innerGroup {
-    //       optional int32 leaf3;
-    //     }
-    //   }
-    parquet_fields.push_back(
-        PrimitiveNode::Make("leaf1", Repetition::OPTIONAL, ParquetType::INT32));
-    parquet_fields.push_back(GroupNode::Make(
-        "outerGroup", Repetition::REPEATED,
-        {PrimitiveNode::Make("leaf2", Repetition::OPTIONAL, ParquetType::INT32),
-         GroupNode::Make(
-             "innerGroup", Repetition::REPEATED,
-             {PrimitiveNode::Make("leaf3", Repetition::OPTIONAL, ParquetType::INT32)})}));
-
-    auto inner_group_fields = {std::make_shared<Field>("leaf3", INT32, true)};
-    auto inner_group_type = std::make_shared<::arrow::StructType>(inner_group_fields);
-    auto outer_group_fields = {
-        std::make_shared<Field>("leaf2", INT32, true),
-        std::make_shared<Field>(
-            "innerGroup",
-            ::arrow::list(std::make_shared<Field>("innerGroup", inner_group_type, false)),
-            false)};
-    auto outer_group_type = std::make_shared<::arrow::StructType>(outer_group_fields);
-
-    arrow_fields.push_back(std::make_shared<Field>("leaf1", INT32, true));
-    arrow_fields.push_back(std::make_shared<Field>(
-        "outerGroup",
-        ::arrow::list(std::make_shared<Field>("outerGroup", outer_group_type, false)),
-        false));
-  }
-  auto arrow_schema = std::make_shared<::arrow::Schema>(arrow_fields);
-  ASSERT_OK(ConvertSchema(parquet_fields));
-
-  ASSERT_NO_FATAL_FAILURE(CheckFlatSchema(arrow_schema));
-}
-
-class TestConvertArrowSchema : public ::testing::Test {
- public:
-  virtual void SetUp() {}
-
-  void CheckFlatSchema(const std::vector<NodePtr>& nodes) {
-    NodePtr schema_node = GroupNode::Make("schema", Repetition::REPEATED, nodes);
-    const GroupNode* expected_schema_node =
-        static_cast<const GroupNode*>(schema_node.get());
-    const GroupNode* result_schema_node = result_schema_->group_node();
-
-    ASSERT_EQ(expected_schema_node->field_count(), result_schema_node->field_count());
-
-    for (int i = 0; i < expected_schema_node->field_count(); i++) {
-      auto lhs = result_schema_node->field(i);
-      auto rhs = expected_schema_node->field(i);
-      EXPECT_TRUE(lhs->Equals(rhs.get()));
-    }
-  }
-
-  ::arrow::Status ConvertSchema(const std::vector<std::shared_ptr<Field>>& fields) {
-    arrow_schema_ = std::make_shared<::arrow::Schema>(fields);
-    std::shared_ptr<::parquet::WriterProperties> properties =
-        ::parquet::default_writer_properties();
-    return ToParquetSchema(arrow_schema_.get(), *properties.get(), &result_schema_);
-  }
-
- protected:
-  std::shared_ptr<::arrow::Schema> arrow_schema_;
-  std::shared_ptr<SchemaDescriptor> result_schema_;
-};
-
-TEST_F(TestConvertArrowSchema, ParquetFlatPrimitives) {
-  std::vector<NodePtr> parquet_fields;
-  std::vector<std::shared_ptr<Field>> arrow_fields;
-
-  parquet_fields.push_back(
-      PrimitiveNode::Make("boolean", Repetition::REQUIRED, ParquetType::BOOLEAN));
-  arrow_fields.push_back(std::make_shared<Field>("boolean", BOOL, false));
-
-  parquet_fields.push_back(
-      PrimitiveNode::Make("int32", Repetition::REQUIRED, ParquetType::INT32));
-  arrow_fields.push_back(std::make_shared<Field>("int32", INT32, false));
-
-  parquet_fields.push_back(
-      PrimitiveNode::Make("int64", Repetition::REQUIRED, ParquetType::INT64));
-  arrow_fields.push_back(std::make_shared<Field>("int64", INT64, false));
-
-  parquet_fields.push_back(PrimitiveNode::Make("date", Repetition::REQUIRED,
-                                               ParquetType::INT32, LogicalType::DATE));
-  arrow_fields.push_back(std::make_shared<Field>("date", ::arrow::date32(), false));
-
-  parquet_fields.push_back(PrimitiveNode::Make("date64", Repetition::REQUIRED,
-                                               ParquetType::INT32, LogicalType::DATE));
-  arrow_fields.push_back(std::make_shared<Field>("date64", ::arrow::date64(), false));
-
-  parquet_fields.push_back(PrimitiveNode::Make("timestamp", Repetition::REQUIRED,
-                                               ParquetType::INT64,
-                                               LogicalType::TIMESTAMP_MILLIS));
-  arrow_fields.push_back(std::make_shared<Field>("timestamp", TIMESTAMP_MS, false));
-
-  parquet_fields.push_back(PrimitiveNode::Make("timestamp[us]", Repetition::REQUIRED,
-                                               ParquetType::INT64,
-                                               LogicalType::TIMESTAMP_MICROS));
-  arrow_fields.push_back(std::make_shared<Field>("timestamp[us]", TIMESTAMP_US, false));
-
-  parquet_fields.push_back(
-      PrimitiveNode::Make("float", Repetition::OPTIONAL, ParquetType::FLOAT));
-  arrow_fields.push_back(std::make_shared<Field>("float", FLOAT));
-
-  parquet_fields.push_back(
-      PrimitiveNode::Make("double", Repetition::OPTIONAL, ParquetType::DOUBLE));
-  arrow_fields.push_back(std::make_shared<Field>("double", DOUBLE));
-
-  parquet_fields.push_back(PrimitiveNode::Make(
-      "string", Repetition::OPTIONAL, ParquetType::BYTE_ARRAY, LogicalType::UTF8));
-  arrow_fields.push_back(std::make_shared<Field>("string", UTF8));
-
-  parquet_fields.push_back(PrimitiveNode::Make(
-      "binary", Repetition::OPTIONAL, ParquetType::BYTE_ARRAY, LogicalType::NONE));
-  arrow_fields.push_back(std::make_shared<Field>("binary", BINARY));
-
-  ASSERT_OK(ConvertSchema(arrow_fields));
-
-  ASSERT_NO_FATAL_FAILURE(CheckFlatSchema(parquet_fields));
-}
-
-TEST_F(TestConvertArrowSchema, ParquetFlatPrimitivesAsDictionaries) {
-  std::vector<NodePtr> parquet_fields;
-  std::vector<std::shared_ptr<Field>> arrow_fields;
-  std::shared_ptr<::arrow::Array> dict;
-
-  parquet_fields.push_back(
-      PrimitiveNode::Make("int32", Repetition::REQUIRED, ParquetType::INT32));
-  ArrayFromVector<::arrow::Int32Type, int32_t>(std::vector<int32_t>(), &dict);
-  arrow_fields.push_back(
-      ::arrow::field("int32", ::arrow::dictionary(::arrow::int8(), dict), false));
-
-  parquet_fields.push_back(
-      PrimitiveNode::Make("int64", Repetition::REQUIRED, ParquetType::INT64));
-  ArrayFromVector<::arrow::Int64Type, int64_t>(std::vector<int64_t>(), &dict);
-  arrow_fields.push_back(std::make_shared<Field>(
-      "int64", ::arrow::dictionary(::arrow::int8(), dict), false));
-
-  parquet_fields.push_back(PrimitiveNode::Make("date", Repetition::REQUIRED,
-                                               ParquetType::INT32, LogicalType::DATE));
-  ArrayFromVector<::arrow::Date32Type, int32_t>(std::vector<int32_t>(), &dict);
-  arrow_fields.push_back(
-      std::make_shared<Field>("date", ::arrow::dictionary(::arrow::int8(), dict), false));
-
-  parquet_fields.push_back(PrimitiveNode::Make("date64", Repetition::REQUIRED,
-                                               ParquetType::INT32, LogicalType::DATE));
-  ArrayFromVector<::arrow::Date64Type, int64_t>(std::vector<int64_t>(), &dict);
-  arrow_fields.push_back(std::make_shared<Field>(
-      "date64", ::arrow::dictionary(::arrow::int8(), dict), false));
-
-  parquet_fields.push_back(
-      PrimitiveNode::Make("float", Repetition::OPTIONAL, ParquetType::FLOAT));
-  ArrayFromVector<::arrow::FloatType, float>(std::vector<float>(), &dict);
-  arrow_fields.push_back(
-      std::make_shared<Field>("float", ::arrow::dictionary(::arrow::int8(), dict)));
-
-  parquet_fields.push_back(
-      PrimitiveNode::Make("double", Repetition::OPTIONAL, ParquetType::DOUBLE));
-  ArrayFromVector<::arrow::DoubleType, double>(std::vector<double>(), &dict);
-  arrow_fields.push_back(
-      std::make_shared<Field>("double", ::arrow::dictionary(::arrow::int8(), dict)));
-
-  parquet_fields.push_back(PrimitiveNode::Make(
-      "string", Repetition::OPTIONAL, ParquetType::BYTE_ARRAY, LogicalType::UTF8));
-  ::arrow::StringBuilder string_builder(::arrow::default_memory_pool());
-  ASSERT_OK(string_builder.Finish(&dict));
-  arrow_fields.push_back(
-      std::make_shared<Field>("string", ::arrow::dictionary(::arrow::int8(), dict)));
-
-  parquet_fields.push_back(PrimitiveNode::Make(
-      "binary", Repetition::OPTIONAL, ParquetType::BYTE_ARRAY, LogicalType::NONE));
-  ::arrow::BinaryBuilder binary_builder(::arrow::default_memory_pool());
-  ASSERT_OK(binary_builder.Finish(&dict));
-  arrow_fields.push_back(
-      std::make_shared<Field>("binary", ::arrow::dictionary(::arrow::int8(), dict)));
-
-  ASSERT_OK(ConvertSchema(arrow_fields));
-
-  ASSERT_NO_FATAL_FAILURE(CheckFlatSchema(parquet_fields));
-}
-
-TEST_F(TestConvertArrowSchema, ParquetLists) {
-  std::vector<NodePtr> parquet_fields;
-  std::vector<std::shared_ptr<Field>> arrow_fields;
-
-  // parquet_arrow will always generate 3-level LIST encodings
-
-  // // List<String> (list non-null, elements nullable)
-  // required group my_list (LIST) {
-  //   repeated group list {
-  //     optional binary element (UTF8);
-  //   }
-  // }
-  {
-    auto element = PrimitiveNode::Make("string", Repetition::OPTIONAL,
-                                       ParquetType::BYTE_ARRAY, LogicalType::UTF8);
-    auto list = GroupNode::Make("list", Repetition::REPEATED, {element});
-    parquet_fields.push_back(
-        GroupNode::Make("my_list", Repetition::REQUIRED, {list}, LogicalType::LIST));
-    auto arrow_element = std::make_shared<Field>("string", UTF8, true);
-    auto arrow_list = std::make_shared<::arrow::ListType>(arrow_element);
-    arrow_fields.push_back(std::make_shared<Field>("my_list", arrow_list, false));
-  }
-
-  // // List<String> (list nullable, elements non-null)
-  // optional group my_list (LIST) {
-  //   repeated group list {
-  //     required binary element (UTF8);
-  //   }
-  // }
-  {
-    auto element = PrimitiveNode::Make("string", Repetition::REQUIRED,
-                                       ParquetType::BYTE_ARRAY, LogicalType::UTF8);
-    auto list = GroupNode::Make("list", Repetition::REPEATED, {element});
-    parquet_fields.push_back(
-        GroupNode::Make("my_list", Repetition::OPTIONAL, {list}, LogicalType::LIST));
-    auto arrow_element = std::make_shared<Field>("string", UTF8, false);
-    auto arrow_list = std::make_shared<::arrow::ListType>(arrow_element);
-    arrow_fields.push_back(std::make_shared<Field>("my_list", arrow_list, true));
-  }
-
-  ASSERT_OK(ConvertSchema(arrow_fields));
-
-  ASSERT_NO_FATAL_FAILURE(CheckFlatSchema(parquet_fields));
-}
-
-TEST_F(TestConvertArrowSchema, UnsupportedTypes) {
-  std::vector<std::shared_ptr<Field>> unsupported_fields = {
-      ::arrow::field("f0", ::arrow::time64(TimeUnit::NANO))};
-
-  for (const auto& field : unsupported_fields) {
-    ASSERT_RAISES(NotImplemented, ConvertSchema({field}));
-  }
-}
-
-TEST_F(TestConvertArrowSchema, ParquetFlatDecimals) {
-  std::vector<NodePtr> parquet_fields;
-  std::vector<std::shared_ptr<Field>> arrow_fields;
-
-  // TODO: Test Decimal Arrow -> Parquet conversion
-
-  ASSERT_OK(ConvertSchema(arrow_fields));
-
-  ASSERT_NO_FATAL_FAILURE(CheckFlatSchema(parquet_fields));
-}
-
-TEST(InvalidSchema, ParquetNegativeDecimalScale) {
-  const auto& type = ::arrow::decimal(23, -2);
-  const auto& field = ::arrow::field("f0", type);
-  const auto& arrow_schema = ::arrow::schema({field});
-  std::shared_ptr<::parquet::WriterProperties> properties =
-      ::parquet::default_writer_properties();
-  std::shared_ptr<SchemaDescriptor> result_schema;
-
-  ASSERT_RAISES(IOError,
-                ToParquetSchema(arrow_schema.get(), *properties.get(), &result_schema));
-}
-
-}  // namespace arrow
-}  // namespace parquet
diff --git a/src/parquet/arrow/reader.cc b/src/parquet/arrow/reader.cc
deleted file mode 100644
index 2e4dc81..0000000
--- a/src/parquet/arrow/reader.cc
+++ /dev/null
@@ -1,1558 +0,0 @@
-// 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.
-
-#include "parquet/arrow/reader.h"
-
-#include <algorithm>
-#include <atomic>
-#include <chrono>
-#include <mutex>
-#include <queue>
-#include <string>
-#include <thread>
-#include <type_traits>
-#include <vector>
-
-#include "arrow/api.h"
-#include "arrow/util/bit-util.h"
-#include "arrow/util/decimal.h"
-#include "arrow/util/logging.h"
-#include "arrow/util/thread-pool.h"
-
-#include "parquet/arrow/record_reader.h"
-#include "parquet/arrow/schema.h"
-#include "parquet/column_reader.h"
-#include "parquet/schema.h"
-#include "parquet/util/schema-util.h"
-
-using arrow::Array;
-using arrow::BooleanArray;
-using arrow::Column;
-using arrow::Field;
-using arrow::Int32Array;
-using arrow::ListArray;
-using arrow::MemoryPool;
-using arrow::ResizableBuffer;
-using arrow::Status;
-using arrow::StructArray;
-using arrow::Table;
-using arrow::TimestampArray;
-
-using parquet::schema::Node;
-
-// Help reduce verbosity
-using ParquetReader = parquet::ParquetFileReader;
-using arrow::RecordBatchReader;
-
-using parquet::internal::RecordReader;
-
-namespace parquet {
-namespace arrow {
-
-using ::arrow::BitUtil::BytesForBits;
-
-constexpr int64_t kJulianToUnixEpochDays = 2440588LL;
-constexpr int64_t kMillisecondsInADay = 86400000LL;
-constexpr int64_t kNanosecondsInADay = kMillisecondsInADay * 1000LL * 1000LL;
-
-static inline int64_t impala_timestamp_to_nanoseconds(const Int96& impala_timestamp) {
-  int64_t days_since_epoch = impala_timestamp.value[2] - kJulianToUnixEpochDays;
-  int64_t nanoseconds = *(reinterpret_cast<const int64_t*>(&(impala_timestamp.value)));
-  return days_since_epoch * kNanosecondsInADay + nanoseconds;
-}
-
-template <typename ArrowType>
-using ArrayType = typename ::arrow::TypeTraits<ArrowType>::ArrayType;
-
-// ----------------------------------------------------------------------
-// Iteration utilities
-
-// Abstraction to decouple row group iteration details from the ColumnReader,
-// so we can read only a single row group if we want
-class FileColumnIterator {
- public:
-  explicit FileColumnIterator(int column_index, ParquetFileReader* reader)
-      : column_index_(column_index),
-        reader_(reader),
-        schema_(reader->metadata()->schema()) {}
-
-  virtual ~FileColumnIterator() {}
-
-  virtual std::unique_ptr<::parquet::PageReader> NextChunk() = 0;
-
-  const SchemaDescriptor* schema() const { return schema_; }
-
-  const ColumnDescriptor* descr() const { return schema_->Column(column_index_); }
-
-  std::shared_ptr<FileMetaData> metadata() const { return reader_->metadata(); }
-
-  int column_index() const { return column_index_; }
-
- protected:
-  int column_index_;
-  ParquetFileReader* reader_;
-  const SchemaDescriptor* schema_;
-};
-
-class AllRowGroupsIterator : public FileColumnIterator {
- public:
-  explicit AllRowGroupsIterator(int column_index, ParquetFileReader* reader)
-      : FileColumnIterator(column_index, reader), next_row_group_(0) {}
-
-  std::unique_ptr<::parquet::PageReader> NextChunk() override {
-    std::unique_ptr<::parquet::PageReader> result;
-    if (next_row_group_ < reader_->metadata()->num_row_groups()) {
-      result = reader_->RowGroup(next_row_group_)->GetColumnPageReader(column_index_);
-      next_row_group_++;
-    } else {
-      result = nullptr;
-    }
-    return result;
-  }
-
- private:
-  int next_row_group_;
-};
-
-class SingleRowGroupIterator : public FileColumnIterator {
- public:
-  explicit SingleRowGroupIterator(int column_index, int row_group_number,
-                                  ParquetFileReader* reader)
-      : FileColumnIterator(column_index, reader),
-        row_group_number_(row_group_number),
-        done_(false) {}
-
-  std::unique_ptr<::parquet::PageReader> NextChunk() override {
-    if (done_) {
-      return nullptr;
-    }
-
-    auto result =
-        reader_->RowGroup(row_group_number_)->GetColumnPageReader(column_index_);
-    done_ = true;
-    return result;
-  }
-
- private:
-  int row_group_number_;
-  bool done_;
-};
-
-class RowGroupRecordBatchReader : public ::arrow::RecordBatchReader {
- public:
-  explicit RowGroupRecordBatchReader(const std::vector<int>& row_group_indices,
-                                     const std::vector<int>& column_indices,
-                                     std::shared_ptr<::arrow::Schema> schema,
-                                     FileReader* reader)
-      : row_group_indices_(row_group_indices),
-        column_indices_(column_indices),
-        schema_(schema),
-        file_reader_(reader),
-        next_row_group_(0) {}
-
-  ~RowGroupRecordBatchReader() override {}
-
-  std::shared_ptr<::arrow::Schema> schema() const override { return schema_; }
-
-  Status ReadNext(std::shared_ptr<::arrow::RecordBatch>* out) override {
-    if (table_ != nullptr) {  // one row group has been loaded
-      std::shared_ptr<::arrow::RecordBatch> tmp;
-      RETURN_NOT_OK(table_batch_reader_->ReadNext(&tmp));
-      if (tmp != nullptr) {  // some column chunks are left in table
-        *out = tmp;
-        return Status::OK();
-      } else {  // the entire table is consumed
-        table_batch_reader_.reset();
-        table_.reset();
-      }
-    }
-
-    // all row groups has been consumed
-    if (next_row_group_ == row_group_indices_.size()) {
-      *out = nullptr;
-      return Status::OK();
-    }
-
-    RETURN_NOT_OK(file_reader_->ReadRowGroup(row_group_indices_[next_row_group_],
-                                             column_indices_, &table_));
-
-    next_row_group_++;
-    table_batch_reader_.reset(new ::arrow::TableBatchReader(*table_.get()));
-    return table_batch_reader_->ReadNext(out);
-  }
-
- private:
-  std::vector<int> row_group_indices_;
-  std::vector<int> column_indices_;
-  std::shared_ptr<::arrow::Schema> schema_;
-  FileReader* file_reader_;
-  size_t next_row_group_;
-  std::shared_ptr<::arrow::Table> table_;
-  std::unique_ptr<::arrow::TableBatchReader> table_batch_reader_;
-};
-
-// ----------------------------------------------------------------------
-// File reader implementation
-
-class FileReader::Impl {
- public:
-  Impl(MemoryPool* pool, std::unique_ptr<ParquetFileReader> reader)
-      : pool_(pool), reader_(std::move(reader)), use_threads_(false) {}
-
-  virtual ~Impl() {}
-
-  Status GetColumn(int i, std::unique_ptr<ColumnReader>* out);
-  Status ReadSchemaField(int i, std::shared_ptr<Array>* out);
-  Status ReadSchemaField(int i, const std::vector<int>& indices,
-                         std::shared_ptr<Array>* out);
-  Status GetReaderForNode(int index, const Node* node, const std::vector<int>& indices,
-                          int16_t def_level,
-                          std::unique_ptr<ColumnReader::ColumnReaderImpl>* out);
-  Status ReadColumn(int i, std::shared_ptr<Array>* out);
-  Status ReadColumnChunk(int column_index, int row_group_index,
-                         std::shared_ptr<Array>* out);
-  Status GetSchema(std::shared_ptr<::arrow::Schema>* out);
-  Status GetSchema(const std::vector<int>& indices,
-                   std::shared_ptr<::arrow::Schema>* out);
-  Status ReadRowGroup(int row_group_index, std::shared_ptr<Table>* table);
-  Status ReadRowGroup(int row_group_index, const std::vector<int>& indices,
-                      std::shared_ptr<::arrow::Table>* out);
-  Status ReadTable(const std::vector<int>& indices, std::shared_ptr<Table>* table);
-  Status ReadTable(std::shared_ptr<Table>* table);
-  Status ReadRowGroups(const std::vector<int>& row_groups, std::shared_ptr<Table>* table);
-  Status ReadRowGroups(const std::vector<int>& row_groups,
-                       const std::vector<int>& indices,
-                       std::shared_ptr<::arrow::Table>* out);
-
-  bool CheckForFlatColumn(const ColumnDescriptor* descr);
-  bool CheckForFlatListColumn(const ColumnDescriptor* descr);
-
-  const ParquetFileReader* parquet_reader() const { return reader_.get(); }
-
-  int num_row_groups() const { return reader_->metadata()->num_row_groups(); }
-
-  int num_columns() const { return reader_->metadata()->num_columns(); }
-
-  void set_use_threads(bool use_threads) { use_threads_ = use_threads; }
-
-  ParquetFileReader* reader() { return reader_.get(); }
-
- private:
-  MemoryPool* pool_;
-  std::unique_ptr<ParquetFileReader> reader_;
-  bool use_threads_;
-};
-
-class ColumnReader::ColumnReaderImpl {
- public:
-  virtual ~ColumnReaderImpl() {}
-  virtual Status NextBatch(int64_t records_to_read, std::shared_ptr<Array>* out) = 0;
-  virtual Status GetDefLevels(const int16_t** data, size_t* length) = 0;
-  virtual Status GetRepLevels(const int16_t** data, size_t* length) = 0;
-  virtual const std::shared_ptr<Field> field() = 0;
-};
-
-// Reader implementation for primitive arrays
-class PARQUET_NO_EXPORT PrimitiveImpl : public ColumnReader::ColumnReaderImpl {
- public:
-  PrimitiveImpl(MemoryPool* pool, std::unique_ptr<FileColumnIterator> input)
-      : pool_(pool), input_(std::move(input)), descr_(input_->descr()) {
-    record_reader_ = RecordReader::Make(descr_, pool_);
-    DCHECK(NodeToField(*input_->descr()->schema_node(), &field_).ok());
-    NextRowGroup();
-  }
-
-  Status NextBatch(int64_t records_to_read, std::shared_ptr<Array>* out) override;
-
-  template <typename ParquetType>
-  Status WrapIntoListArray(std::shared_ptr<Array>* array);
-
-  Status GetDefLevels(const int16_t** data, size_t* length) override;
-  Status GetRepLevels(const int16_t** data, size_t* length) override;
-
-  const std::shared_ptr<Field> field() override { return field_; }
-
- private:
-  void NextRowGroup();
-
-  MemoryPool* pool_;
-  std::unique_ptr<FileColumnIterator> input_;
-  const ColumnDescriptor* descr_;
-
-  std::shared_ptr<RecordReader> record_reader_;
-
-  std::shared_ptr<Field> field_;
-};
-
-// Reader implementation for struct array
-class PARQUET_NO_EXPORT StructImpl : public ColumnReader::ColumnReaderImpl {
- public:
-  explicit StructImpl(const std::vector<std::shared_ptr<ColumnReaderImpl>>& children,
-                      int16_t struct_def_level, MemoryPool* pool, const Node* node)
-      : children_(children), struct_def_level_(struct_def_level), pool_(pool) {
-    InitField(node, children);
-  }
-
-  Status NextBatch(int64_t records_to_read, std::shared_ptr<Array>* out) override;
-  Status GetDefLevels(const int16_t** data, size_t* length) override;
-  Status GetRepLevels(const int16_t** data, size_t* length) override;
-  const std::shared_ptr<Field> field() override { return field_; }
-
- private:
-  std::vector<std::shared_ptr<ColumnReaderImpl>> children_;
-  int16_t struct_def_level_;
-  MemoryPool* pool_;
-  std::shared_ptr<Field> field_;
-  std::shared_ptr<ResizableBuffer> def_levels_buffer_;
-
-  Status DefLevelsToNullArray(std::shared_ptr<Buffer>* null_bitmap, int64_t* null_count);
-  void InitField(const Node* node,
-                 const std::vector<std::shared_ptr<ColumnReaderImpl>>& children);
-};
-
-FileReader::FileReader(MemoryPool* pool, std::unique_ptr<ParquetFileReader> reader)
-    : impl_(new FileReader::Impl(pool, std::move(reader))) {}
-
-FileReader::~FileReader() {}
-
-Status FileReader::Impl::GetColumn(int i, std::unique_ptr<ColumnReader>* out) {
-  std::unique_ptr<FileColumnIterator> input(new AllRowGroupsIterator(i, reader_.get()));
-
-  std::unique_ptr<ColumnReader::ColumnReaderImpl> impl(
-      new PrimitiveImpl(pool_, std::move(input)));
-  *out = std::unique_ptr<ColumnReader>(new ColumnReader(std::move(impl)));
-  return Status::OK();
-}
-
-Status FileReader::Impl::GetReaderForNode(
-    int index, const Node* node, const std::vector<int>& indices, int16_t def_level,
-    std::unique_ptr<ColumnReader::ColumnReaderImpl>* out) {
-  *out = nullptr;
-
-  if (IsSimpleStruct(node)) {
-    const schema::GroupNode* group = static_cast<const schema::GroupNode*>(node);
-    std::vector<std::shared_ptr<ColumnReader::ColumnReaderImpl>> children;
-    for (int i = 0; i < group->field_count(); i++) {
-      std::unique_ptr<ColumnReader::ColumnReaderImpl> child_reader;
-      // TODO(itaiin): Remove the -1 index hack when all types of nested reads
-      // are supported. This currently just signals the lower level reader resolution
-      // to abort
-      RETURN_NOT_OK(GetReaderForNode(index, group->field(i).get(), indices,
-                                     static_cast<int16_t>(def_level + 1), &child_reader));
-      if (child_reader != nullptr) {
-        children.push_back(std::move(child_reader));
-      }
-    }
-
-    if (children.size() > 0) {
-      *out = std::unique_ptr<ColumnReader::ColumnReaderImpl>(
-          new StructImpl(children, def_level, pool_, node));
-    }
-  } else {
-    // This should be a flat field case - translate the field index to
-    // the correct column index by walking down to the leaf node
-    const Node* walker = node;
-    while (!walker->is_primitive()) {
-      DCHECK(walker->is_group());
-      auto group = static_cast<const GroupNode*>(walker);
-      if (group->field_count() != 1) {
-        return Status::NotImplemented("lists with structs are not supported.");
-      }
-      walker = group->field(0).get();
-    }
-    auto column_index = reader_->metadata()->schema()->ColumnIndex(*walker);
-
-    // If the index of the column is found then a reader for the coliumn is needed.
-    // Otherwise *out keeps the nullptr value.
-    if (std::find(indices.begin(), indices.end(), column_index) != indices.end()) {
-      std::unique_ptr<ColumnReader> reader;
-      RETURN_NOT_OK(GetColumn(column_index, &reader));
-      *out = std::move(reader->impl_);
-    }
-  }
-
-  return Status::OK();
-}
-
-Status FileReader::Impl::ReadSchemaField(int i, std::shared_ptr<Array>* out) {
-  std::vector<int> indices(reader_->metadata()->num_columns());
-
-  for (size_t j = 0; j < indices.size(); ++j) {
-    indices[j] = static_cast<int>(j);
-  }
-
-  return ReadSchemaField(i, indices, out);
-}
-
-Status FileReader::Impl::ReadSchemaField(int i, const std::vector<int>& indices,
-                                         std::shared_ptr<Array>* out) {
-  auto parquet_schema = reader_->metadata()->schema();
-
-  auto node = parquet_schema->group_node()->field(i).get();
-  std::unique_ptr<ColumnReader::ColumnReaderImpl> reader_impl;
-
-  RETURN_NOT_OK(GetReaderForNode(i, node, indices, 1, &reader_impl));
-  if (reader_impl == nullptr) {
-    *out = nullptr;
-    return Status::OK();
-  }
-
-  std::unique_ptr<ColumnReader> reader(new ColumnReader(std::move(reader_impl)));
-
-  // TODO(wesm): This calculation doesn't make much sense when we have repeated
-  // schema nodes
-  int64_t records_to_read = 0;
-
-  const FileMetaData& metadata = *reader_->metadata();
-  for (int j = 0; j < metadata.num_row_groups(); j++) {
-    records_to_read += metadata.RowGroup(j)->ColumnChunk(i)->num_values();
-  }
-
-  return reader->NextBatch(records_to_read, out);
-}
-
-Status FileReader::Impl::ReadColumn(int i, std::shared_ptr<Array>* out) {
-  std::unique_ptr<ColumnReader> flat_column_reader;
-  RETURN_NOT_OK(GetColumn(i, &flat_column_reader));
-
-  int64_t records_to_read = 0;
-  for (int j = 0; j < reader_->metadata()->num_row_groups(); j++) {
-    records_to_read += reader_->metadata()->RowGroup(j)->ColumnChunk(i)->num_values();
-  }
-
-  return flat_column_reader->NextBatch(records_to_read, out);
-}
-
-Status FileReader::Impl::GetSchema(const std::vector<int>& indices,
-                                   std::shared_ptr<::arrow::Schema>* out) {
-  auto descr = reader_->metadata()->schema();
-  auto parquet_key_value_metadata = reader_->metadata()->key_value_metadata();
-  return FromParquetSchema(descr, indices, parquet_key_value_metadata, out);
-}
-
-Status FileReader::Impl::ReadColumnChunk(int column_index, int row_group_index,
-                                         std::shared_ptr<Array>* out) {
-  auto rg_metadata = reader_->metadata()->RowGroup(row_group_index);
-  int64_t records_to_read = rg_metadata->ColumnChunk(column_index)->num_values();
-
-  std::unique_ptr<FileColumnIterator> input(
-      new SingleRowGroupIterator(column_index, row_group_index, reader_.get()));
-
-  std::unique_ptr<ColumnReader::ColumnReaderImpl> impl(
-      new PrimitiveImpl(pool_, std::move(input)));
-  ColumnReader flat_column_reader(std::move(impl));
-
-  std::shared_ptr<Array> array;
-  RETURN_NOT_OK(flat_column_reader.NextBatch(records_to_read, &array));
-  *out = array;
-  return Status::OK();
-}
-
-Status FileReader::Impl::ReadRowGroup(int row_group_index,
-                                      const std::vector<int>& indices,
-                                      std::shared_ptr<Table>* out) {
-  std::shared_ptr<::arrow::Schema> schema;
-  RETURN_NOT_OK(GetSchema(indices, &schema));
-
-  auto rg_metadata = reader_->metadata()->RowGroup(row_group_index);
-
-  int num_columns = static_cast<int>(indices.size());
-  std::vector<std::shared_ptr<Column>> columns(num_columns);
-
-  // TODO(wesm): Refactor to share more code with ReadTable
-
-  auto ReadColumnFunc = [&indices, &row_group_index, &schema, &columns, this](int i) {
-    int column_index = indices[i];
-
-    std::shared_ptr<Array> array;
-    RETURN_NOT_OK(ReadColumnChunk(column_index, row_group_index, &array));
-    columns[i] = std::make_shared<Column>(schema->field(i), array);
-    return Status::OK();
-  };
-
-  if (use_threads_) {
-    std::vector<std::future<Status>> futures;
-    auto pool = ::arrow::internal::GetCpuThreadPool();
-    for (int i = 0; i < num_columns; i++) {
-      futures.push_back(pool->Submit(ReadColumnFunc, i));
-    }
-    Status final_status = Status::OK();
-    for (auto& fut : futures) {
-      Status st = fut.get();
-      if (!st.ok()) {
-        final_status = std::move(st);
-      }
-    }
-    RETURN_NOT_OK(final_status);
-  } else {
-    for (int i = 0; i < num_columns; i++) {
-      RETURN_NOT_OK(ReadColumnFunc(i));
-    }
-  }
-
-  *out = Table::Make(schema, columns);
-  return Status::OK();
-}
-
-Status FileReader::Impl::ReadTable(const std::vector<int>& indices,
-                                   std::shared_ptr<Table>* out) {
-  std::shared_ptr<::arrow::Schema> schema;
-  RETURN_NOT_OK(GetSchema(indices, &schema));
-
-  // We only need to read schema fields which have columns indicated
-  // in the indices vector
-  std::vector<int> field_indices;
-  if (!ColumnIndicesToFieldIndices(*reader_->metadata()->schema(), indices,
-                                   &field_indices)) {
-    return Status::Invalid("Invalid column index");
-  }
-
-  int num_fields = static_cast<int>(field_indices.size());
-  std::vector<std::shared_ptr<Column>> columns(num_fields);
-
-  auto ReadColumnFunc = [&indices, &field_indices, &schema, &columns, this](int i) {
-    std::shared_ptr<Array> array;
-    RETURN_NOT_OK(ReadSchemaField(field_indices[i], indices, &array));
-    columns[i] = std::make_shared<Column>(schema->field(i), array);
-    return Status::OK();
-  };
-
-  if (use_threads_) {
-    std::vector<std::future<Status>> futures;
-    auto pool = ::arrow::internal::GetCpuThreadPool();
-    for (int i = 0; i < num_fields; i++) {
-      futures.push_back(pool->Submit(ReadColumnFunc, i));
-    }
-    Status final_status = Status::OK();
-    for (auto& fut : futures) {
-      Status st = fut.get();
-      if (!st.ok()) {
-        final_status = std::move(st);
-      }
-    }
-    RETURN_NOT_OK(final_status);
-  } else {
-    for (int i = 0; i < num_fields; i++) {
-      RETURN_NOT_OK(ReadColumnFunc(i));
-    }
-  }
-
-  std::shared_ptr<Table> table = Table::Make(schema, columns);
-  RETURN_NOT_OK(table->Validate());
-  *out = table;
-  return Status::OK();
-}
-
-Status FileReader::Impl::ReadTable(std::shared_ptr<Table>* table) {
-  std::vector<int> indices(reader_->metadata()->num_columns());
-
-  for (size_t i = 0; i < indices.size(); ++i) {
-    indices[i] = static_cast<int>(i);
-  }
-  return ReadTable(indices, table);
-}
-
-Status FileReader::Impl::ReadRowGroups(const std::vector<int>& row_groups,
-                                       const std::vector<int>& indices,
-                                       std::shared_ptr<Table>* table) {
-  // TODO(PARQUET-1393): Modify the record readers to already read this into a single,
-  // continuous array.
-  std::vector<std::shared_ptr<Table>> tables(row_groups.size(), nullptr);
-
-  for (size_t i = 0; i < row_groups.size(); ++i) {
-    RETURN_NOT_OK(ReadRowGroup(row_groups[i], indices, &tables[i]));
-  }
-  return ConcatenateTables(tables, table);
-}
-
-Status FileReader::Impl::ReadRowGroups(const std::vector<int>& row_groups,
-                                       std::shared_ptr<Table>* table) {
-  std::vector<int> indices(reader_->metadata()->num_columns());
-
-  for (size_t i = 0; i < indices.size(); ++i) {
-    indices[i] = static_cast<int>(i);
-  }
-  return ReadRowGroups(row_groups, indices, table);
-}
-
-Status FileReader::Impl::ReadRowGroup(int i, std::shared_ptr<Table>* table) {
-  std::vector<int> indices(reader_->metadata()->num_columns());
-
-  for (size_t i = 0; i < indices.size(); ++i) {
-    indices[i] = static_cast<int>(i);
-  }
-  return ReadRowGroup(i, indices, table);
-}
-
-// Static ctor
-Status OpenFile(const std::shared_ptr<::arrow::io::ReadableFileInterface>& file,
-                MemoryPool* allocator, const ReaderProperties& props,
-                const std::shared_ptr<FileMetaData>& metadata,
-                std::unique_ptr<FileReader>* reader) {
-  std::unique_ptr<RandomAccessSource> io_wrapper(new ArrowInputFile(file));
-  std::unique_ptr<ParquetReader> pq_reader;
-  PARQUET_CATCH_NOT_OK(pq_reader =
-                           ParquetReader::Open(std::move(io_wrapper), props, metadata));
-  reader->reset(new FileReader(allocator, std::move(pq_reader)));
-  return Status::OK();
-}
-
-Status OpenFile(const std::shared_ptr<::arrow::io::ReadableFileInterface>& file,
-                MemoryPool* allocator, std::unique_ptr<FileReader>* reader) {
-  return OpenFile(file, allocator, ::parquet::default_reader_properties(), nullptr,
-                  reader);
-}
-
-Status FileReader::GetColumn(int i, std::unique_ptr<ColumnReader>* out) {
-  return impl_->GetColumn(i, out);
-}
-
-Status FileReader::GetSchema(const std::vector<int>& indices,
-                             std::shared_ptr<::arrow::Schema>* out) {
-  return impl_->GetSchema(indices, out);
-}
-
-Status FileReader::ReadColumn(int i, std::shared_ptr<Array>* out) {
-  try {
-    return impl_->ReadColumn(i, out);
-  } catch (const ::parquet::ParquetException& e) {
-    return ::arrow::Status::IOError(e.what());
-  }
-}
-
-Status FileReader::ReadSchemaField(int i, std::shared_ptr<Array>* out) {
-  try {
-    return impl_->ReadSchemaField(i, out);
-  } catch (const ::parquet::ParquetException& e) {
-    return ::arrow::Status::IOError(e.what());
-  }
-}
-
-Status FileReader::GetRecordBatchReader(const std::vector<int>& row_group_indices,
-                                        std::shared_ptr<RecordBatchReader>* out) {
-  std::vector<int> indices(impl_->num_columns());
-
-  for (size_t j = 0; j < indices.size(); ++j) {
-    indices[j] = static_cast<int>(j);
-  }
-
-  return GetRecordBatchReader(row_group_indices, indices, out);
-}
-
-Status FileReader::GetRecordBatchReader(const std::vector<int>& row_group_indices,
-                                        const std::vector<int>& column_indices,
-                                        std::shared_ptr<RecordBatchReader>* out) {
-  // column indicies check
-  std::shared_ptr<::arrow::Schema> schema;
-  RETURN_NOT_OK(GetSchema(column_indices, &schema));
-
-  // row group indices check
-  int max_num = num_row_groups();
-  for (auto row_group_index : row_group_indices) {
-    if (row_group_index < 0 || row_group_index >= max_num) {
-      std::ostringstream ss;
-      ss << "Some index in row_group_indices is " << row_group_index
-         << ", which is either < 0 or >= num_row_groups(" << max_num << ")";
-      return Status::Invalid(ss.str());
-    }
-  }
-
-  *out = std::make_shared<RowGroupRecordBatchReader>(row_group_indices, column_indices,
-                                                     schema, this);
-  return Status::OK();
-}
-
-Status FileReader::ReadTable(std::shared_ptr<Table>* out) {
-  try {
-    return impl_->ReadTable(out);
-  } catch (const ::parquet::ParquetException& e) {
-    return ::arrow::Status::IOError(e.what());
-  }
-}
-
-Status FileReader::ReadTable(const std::vector<int>& indices,
-                             std::shared_ptr<Table>* out) {
-  try {
-    return impl_->ReadTable(indices, out);
-  } catch (const ::parquet::ParquetException& e) {
-    return ::arrow::Status::IOError(e.what());
-  }
-}
-
-Status FileReader::ReadRowGroup(int i, std::shared_ptr<Table>* out) {
-  try {
-    return impl_->ReadRowGroup(i, out);
-  } catch (const ::parquet::ParquetException& e) {
-    return ::arrow::Status::IOError(e.what());
-  }
-}
-
-Status FileReader::ReadRowGroup(int i, const std::vector<int>& indices,
-                                std::shared_ptr<Table>* out) {
-  try {
-    return impl_->ReadRowGroup(i, indices, out);
-  } catch (const ::parquet::ParquetException& e) {
-    return ::arrow::Status::IOError(e.what());
-  }
-}
-
-Status FileReader::ReadRowGroups(const std::vector<int>& row_groups,
-                                 std::shared_ptr<Table>* out) {
-  try {
-    return impl_->ReadRowGroups(row_groups, out);
-  } catch (const ::parquet::ParquetException& e) {
-    return ::arrow::Status::IOError(e.what());
-  }
-}
-
-Status FileReader::ReadRowGroups(const std::vector<int>& row_groups,
-                                 const std::vector<int>& indices,
-                                 std::shared_ptr<Table>* out) {
-  try {
-    return impl_->ReadRowGroups(row_groups, indices, out);
-  } catch (const ::parquet::ParquetException& e) {
-    return ::arrow::Status::IOError(e.what());
-  }
-}
-
-std::shared_ptr<RowGroupReader> FileReader::RowGroup(int row_group_index) {
-  return std::shared_ptr<RowGroupReader>(
-      new RowGroupReader(impl_.get(), row_group_index));
-}
-
-int FileReader::num_row_groups() const { return impl_->num_row_groups(); }
-
-void FileReader::set_num_threads(int num_threads) {}
-
-void FileReader::set_use_threads(bool use_threads) {
-  impl_->set_use_threads(use_threads);
-}
-
-Status FileReader::ScanContents(std::vector<int> columns, const int32_t column_batch_size,
-                                int64_t* num_rows) {
-  try {
-    *num_rows = ScanFileContents(columns, column_batch_size, impl_->reader());
-    return Status::OK();
-  } catch (const ::parquet::ParquetException& e) {
-    return Status::IOError(e.what());
-  }
-}
-
-const ParquetFileReader* FileReader::parquet_reader() const {
-  return impl_->parquet_reader();
-}
-
-template <typename ParquetType>
-Status PrimitiveImpl::WrapIntoListArray(std::shared_ptr<Array>* array) {
-  const int16_t* def_levels = record_reader_->def_levels();
-  const int16_t* rep_levels = record_reader_->rep_levels();
-  const int64_t total_levels_read = record_reader_->levels_position();
-
-  std::shared_ptr<::arrow::Schema> arrow_schema;
-  RETURN_NOT_OK(FromParquetSchema(input_->schema(), {input_->column_index()},
-                                  input_->metadata()->key_value_metadata(),
-                                  &arrow_schema));
-  std::shared_ptr<Field> current_field = arrow_schema->field(0);
-
-  if (descr_->max_repetition_level() > 0) {
-    // Walk downwards to extract nullability
-    std::vector<bool> nullable;
-    std::vector<std::shared_ptr<::arrow::Int32Builder>> offset_builders;
-    std::vector<std::shared_ptr<::arrow::BooleanBuilder>> valid_bits_builders;
-    nullable.push_back(current_field->nullable());
-    while (current_field->type()->num_children() > 0) {
-      if (current_field->type()->num_children() > 1) {
-        return Status::NotImplemented(
-            "Fields with more than one child are not supported.");
-      } else {
-        if (current_field->type()->id() != ::arrow::Type::LIST) {
-          return Status::NotImplemented(
-              "Currently only nesting with Lists is supported.");
-        }
-        current_field = current_field->type()->child(0);
-      }
-      offset_builders.emplace_back(
-          std::make_shared<::arrow::Int32Builder>(::arrow::int32(), pool_));
-      valid_bits_builders.emplace_back(
-          std::make_shared<::arrow::BooleanBuilder>(::arrow::boolean(), pool_));
-      nullable.push_back(current_field->nullable());
-    }
-
-    int64_t list_depth = offset_builders.size();
-    // This describes the minimal definition that describes a level that
-    // reflects a value in the primitive values array.
-    int16_t values_def_level = descr_->max_definition_level();
-    if (nullable[nullable.size() - 1]) {
-      values_def_level--;
-    }
-
-    // The definition levels that are needed so that a list is declared
-    // as empty and not null.
-    std::vector<int16_t> empty_def_level(list_depth);
-    int def_level = 0;
-    for (int i = 0; i < list_depth; i++) {
-      if (nullable[i]) {
-        def_level++;
-      }
-      empty_def_level[i] = static_cast<int16_t>(def_level);
-      def_level++;
-    }
-
-    int32_t values_offset = 0;
-    std::vector<int64_t> null_counts(list_depth, 0);
-    for (int64_t i = 0; i < total_levels_read; i++) {
-      int16_t rep_level = rep_levels[i];
-      if (rep_level < descr_->max_repetition_level()) {
-        for (int64_t j = rep_level; j < list_depth; j++) {
-          if (j == (list_depth - 1)) {
-            RETURN_NOT_OK(offset_builders[j]->Append(values_offset));
-          } else {
-            RETURN_NOT_OK(offset_builders[j]->Append(
-                static_cast<int32_t>(offset_builders[j + 1]->length())));
-          }
-
-          if (((empty_def_level[j] - 1) == def_levels[i]) && (nullable[j])) {
-            RETURN_NOT_OK(valid_bits_builders[j]->Append(false));
-            null_counts[j]++;
-            break;
-          } else {
-            RETURN_NOT_OK(valid_bits_builders[j]->Append(true));
-            if (empty_def_level[j] == def_levels[i]) {
-              break;
-            }
-          }
-        }
-      }
-      if (def_levels[i] >= values_def_level) {
-        values_offset++;
-      }
-    }
-    // Add the final offset to all lists
-    for (int64_t j = 0; j < list_depth; j++) {
-      if (j == (list_depth - 1)) {
-        RETURN_NOT_OK(offset_builders[j]->Append(values_offset));
-      } else {
-        RETURN_NOT_OK(offset_builders[j]->Append(
-            static_cast<int32_t>(offset_builders[j + 1]->length())));
-      }
-    }
-
-    std::vector<std::shared_ptr<Buffer>> offsets;
-    std::vector<std::shared_ptr<Buffer>> valid_bits;
-    std::vector<int64_t> list_lengths;
-    for (int64_t j = 0; j < list_depth; j++) {
-      list_lengths.push_back(offset_builders[j]->length() - 1);
-      std::shared_ptr<Array> array;
-      RETURN_NOT_OK(offset_builders[j]->Finish(&array));
-      offsets.emplace_back(std::static_pointer_cast<Int32Array>(array)->values());
-      RETURN_NOT_OK(valid_bits_builders[j]->Finish(&array));
-      valid_bits.emplace_back(std::static_pointer_cast<BooleanArray>(array)->values());
-    }
-
-    std::shared_ptr<Array> output(*array);
-    for (int64_t j = list_depth - 1; j >= 0; j--) {
-      auto list_type =
-          ::arrow::list(::arrow::field("item", output->type(), nullable[j + 1]));
-      output = std::make_shared<::arrow::ListArray>(
-          list_type, list_lengths[j], offsets[j], output, valid_bits[j], null_counts[j]);
-    }
-    *array = output;
-  }
-  return Status::OK();
-}
-
-template <typename ArrowType, typename ParquetType>
-struct supports_fast_path_impl {
-  using ArrowCType = typename ArrowType::c_type;
-  using ParquetCType = typename ParquetType::c_type;
-  static constexpr bool value = std::is_same<ArrowCType, ParquetCType>::value;
-};
-
-template <typename ArrowType>
-struct supports_fast_path_impl<ArrowType, ByteArrayType> {
-  static constexpr bool value = false;
-};
-
-template <typename ArrowType>
-struct supports_fast_path_impl<ArrowType, FLBAType> {
-  static constexpr bool value = false;
-};
-
-template <typename ArrowType, typename ParquetType>
-using supports_fast_path =
-    typename std::enable_if<supports_fast_path_impl<ArrowType, ParquetType>::value>::type;
-
-template <typename ArrowType, typename ParquetType, typename Enable = void>
-struct TransferFunctor {
-  using ArrowCType = typename ArrowType::c_type;
-  using ParquetCType = typename ParquetType::c_type;
-
-  Status operator()(RecordReader* reader, MemoryPool* pool,
-                    const std::shared_ptr<::arrow::DataType>& type,
-                    std::shared_ptr<Array>* out) {
-    static_assert(!std::is_same<ArrowType, ::arrow::Int32Type>::value,
-                  "The fast path transfer functor should be used "
-                  "for primitive values");
-
-    int64_t length = reader->values_written();
-    std::shared_ptr<Buffer> data;
-    RETURN_NOT_OK(::arrow::AllocateBuffer(pool, length * sizeof(ArrowCType), &data));
-
-    auto values = reinterpret_cast<const ParquetCType*>(reader->values());
-    auto out_ptr = reinterpret_cast<ArrowCType*>(data->mutable_data());
-    std::copy(values, values + length, out_ptr);
-
-    if (reader->nullable_values()) {
-      std::shared_ptr<ResizableBuffer> is_valid = reader->ReleaseIsValid();
-      *out = std::make_shared<ArrayType<ArrowType>>(type, length, data, is_valid,
-                                                    reader->null_count());
-    } else {
-      *out = std::make_shared<ArrayType<ArrowType>>(type, length, data);
-    }
-    return Status::OK();
-  }
-};
-
-template <typename ArrowType, typename ParquetType>
-struct TransferFunctor<ArrowType, ParquetType,
-                       supports_fast_path<ArrowType, ParquetType>> {
-  Status operator()(RecordReader* reader, MemoryPool* pool,
-                    const std::shared_ptr<::arrow::DataType>& type,
-                    std::shared_ptr<Array>* out) {
-    int64_t length = reader->values_written();
-    std::shared_ptr<ResizableBuffer> values = reader->ReleaseValues();
-
-    if (reader->nullable_values()) {
-      std::shared_ptr<ResizableBuffer> is_valid = reader->ReleaseIsValid();
-      *out = std::make_shared<ArrayType<ArrowType>>(type, length, values, is_valid,
-                                                    reader->null_count());
-    } else {
-      *out = std::make_shared<ArrayType<ArrowType>>(type, length, values);
-    }
-    return Status::OK();
-  }
-};
-
-template <>
-struct TransferFunctor<::arrow::BooleanType, BooleanType> {
-  Status operator()(RecordReader* reader, MemoryPool* pool,
-                    const std::shared_ptr<::arrow::DataType>& type,
-                    std::shared_ptr<Array>* out) {
-    int64_t length = reader->values_written();
-    std::shared_ptr<Buffer> data;
-
-    const int64_t buffer_size = BytesForBits(length);
-    RETURN_NOT_OK(::arrow::AllocateBuffer(pool, buffer_size, &data));
-
-    // Transfer boolean values to packed bitmap
-    auto values = reinterpret_cast<const bool*>(reader->values());
-    uint8_t* data_ptr = data->mutable_data();
-    memset(data_ptr, 0, buffer_size);
-
-    for (int64_t i = 0; i < length; i++) {
-      if (values[i]) {
-        ::arrow::BitUtil::SetBit(data_ptr, i);
-      }
-    }
-
-    if (reader->nullable_values()) {
-      std::shared_ptr<ResizableBuffer> is_valid = reader->ReleaseIsValid();
-      RETURN_NOT_OK(is_valid->Resize(BytesForBits(length), false));
-      *out = std::make_shared<BooleanArray>(type, length, data, is_valid,
-                                            reader->null_count());
-    } else {
-      *out = std::make_shared<BooleanArray>(type, length, data);
-    }
-    return Status::OK();
-  }
-};
-
-template <>
-struct TransferFunctor<::arrow::TimestampType, Int96Type> {
-  Status operator()(RecordReader* reader, MemoryPool* pool,
-                    const std::shared_ptr<::arrow::DataType>& type,
-                    std::shared_ptr<Array>* out) {
-    int64_t length = reader->values_written();
-    auto values = reinterpret_cast<const Int96*>(reader->values());
-
-    std::shared_ptr<Buffer> data;
-    RETURN_NOT_OK(::arrow::AllocateBuffer(pool, length * sizeof(int64_t), &data));
-
-    auto data_ptr = reinterpret_cast<int64_t*>(data->mutable_data());
-    for (int64_t i = 0; i < length; i++) {
-      *data_ptr++ = impala_timestamp_to_nanoseconds(values[i]);
-    }
-
-    if (reader->nullable_values()) {
-      std::shared_ptr<ResizableBuffer> is_valid = reader->ReleaseIsValid();
-      *out = std::make_shared<TimestampArray>(type, length, data, is_valid,
-                                              reader->null_count());
-    } else {
-      *out = std::make_shared<TimestampArray>(type, length, data);
-    }
-
-    return Status::OK();
-  }
-};
-
-template <>
-struct TransferFunctor<::arrow::Date64Type, Int32Type> {
-  Status operator()(RecordReader* reader, MemoryPool* pool,
-                    const std::shared_ptr<::arrow::DataType>& type,
-                    std::shared_ptr<Array>* out) {
-    int64_t length = reader->values_written();
-    auto values = reinterpret_cast<const int32_t*>(reader->values());
-
-    std::shared_ptr<Buffer> data;
-    RETURN_NOT_OK(::arrow::AllocateBuffer(pool, length * sizeof(int64_t), &data));
-    auto out_ptr = reinterpret_cast<int64_t*>(data->mutable_data());
-
-    for (int64_t i = 0; i < length; i++) {
-      *out_ptr++ = static_cast<int64_t>(values[i]) * kMillisecondsInADay;
-    }
-
-    if (reader->nullable_values()) {
-      std::shared_ptr<ResizableBuffer> is_valid = reader->ReleaseIsValid();
-      *out = std::make_shared<::arrow::Date64Array>(type, length, data, is_valid,
-                                                    reader->null_count());
-    } else {
-      *out = std::make_shared<::arrow::Date64Array>(type, length, data);
-    }
-    return Status::OK();
-  }
-};
-
-template <typename ArrowType, typename ParquetType>
-struct TransferFunctor<
-    ArrowType, ParquetType,
-    typename std::enable_if<std::is_same<ParquetType, ByteArrayType>::value ||
-                            std::is_same<ParquetType, FLBAType>::value>::type> {
-  Status operator()(RecordReader* reader, MemoryPool* pool,
-                    const std::shared_ptr<::arrow::DataType>& type,
-                    std::shared_ptr<Array>* out) {
-    RETURN_NOT_OK(reader->builder()->Finish(out));
-
-    if (type->id() == ::arrow::Type::STRING) {
-      // Convert from BINARY type to STRING
-      auto new_data = (*out)->data()->Copy();
-      new_data->type = type;
-      *out = ::arrow::MakeArray(new_data);
-    }
-    return Status::OK();
-  }
-};
-
-static uint64_t BytesToInteger(const uint8_t* bytes, int32_t start, int32_t stop) {
-  using ::arrow::BitUtil::FromBigEndian;
-
-  const int32_t length = stop - start;
-
-  DCHECK_GE(length, 0);
-  DCHECK_LE(length, 8);
-
-  switch (length) {
-    case 0:
-      return 0;
-    case 1:
-      return bytes[start];
-    case 2:
-      return FromBigEndian(*reinterpret_cast<const uint16_t*>(bytes + start));
-    case 3: {
-      const uint64_t first_two_bytes =
-          FromBigEndian(*reinterpret_cast<const uint16_t*>(bytes + start));
-      const uint64_t last_byte = bytes[stop - 1];
-      return first_two_bytes << 8 | last_byte;
-    }
-    case 4:
-      return FromBigEndian(*reinterpret_cast<const uint32_t*>(bytes + start));
-    case 5: {
-      const uint64_t first_four_bytes =
-          FromBigEndian(*reinterpret_cast<const uint32_t*>(bytes + start));
-      const uint64_t last_byte = bytes[stop - 1];
-      return first_four_bytes << 8 | last_byte;
-    }
-    case 6: {
-      const uint64_t first_four_bytes =
-          FromBigEndian(*reinterpret_cast<const uint32_t*>(bytes + start));
-      const uint64_t last_two_bytes =
-          FromBigEndian(*reinterpret_cast<const uint16_t*>(bytes + start + 4));
-      return first_four_bytes << 16 | last_two_bytes;
-    }
-    case 7: {
-      const uint64_t first_four_bytes =
-          FromBigEndian(*reinterpret_cast<const uint32_t*>(bytes + start));
-      const uint64_t second_two_bytes =
-          FromBigEndian(*reinterpret_cast<const uint16_t*>(bytes + start + 4));
-      const uint64_t last_byte = bytes[stop - 1];
-      return first_four_bytes << 24 | second_two_bytes << 8 | last_byte;
-    }
-    case 8:
-      return FromBigEndian(*reinterpret_cast<const uint64_t*>(bytes + start));
-    default: {
-      DCHECK(false);
-      return UINT64_MAX;
-    }
-  }
-}
-
-static constexpr int32_t kMinDecimalBytes = 1;
-static constexpr int32_t kMaxDecimalBytes = 16;
-
-/// \brief Convert a sequence of big-endian bytes to one int64_t (high bits) and one
-/// uint64_t (low bits).
-static void BytesToIntegerPair(const uint8_t* bytes,
-                               const int32_t total_number_of_bytes_used, int64_t* high,
-                               uint64_t* low) {
-  DCHECK_GE(total_number_of_bytes_used, kMinDecimalBytes);
-  DCHECK_LE(total_number_of_bytes_used, kMaxDecimalBytes);
-
-  /// Bytes are coming in big-endian, so the first byte is the MSB and therefore holds the
-  /// sign bit.
-  const bool is_negative = static_cast<int8_t>(bytes[0]) < 0;
-
-  /// Sign extend the low bits if necessary
-  *low = UINT64_MAX * (is_negative && total_number_of_bytes_used < 8);
-  *high = -1 * (is_negative && total_number_of_bytes_used < kMaxDecimalBytes);
-
-  /// Stop byte of the high bytes
-  const int32_t high_bits_offset = std::max(0, total_number_of_bytes_used - 8);
-
-  /// Shift left enough bits to make room for the incoming int64_t
-  *high <<= high_bits_offset * CHAR_BIT;
-
-  /// Preserve the upper bits by inplace OR-ing the int64_t
-  *high |= BytesToInteger(bytes, 0, high_bits_offset);
-
-  /// Stop byte of the low bytes
-  const int32_t low_bits_offset = std::min(total_number_of_bytes_used, 8);
-
-  /// Shift left enough bits to make room for the incoming uint64_t
-  *low <<= low_bits_offset * CHAR_BIT;
-
-  /// Preserve the upper bits by inplace OR-ing the uint64_t
-  *low |= BytesToInteger(bytes, high_bits_offset, total_number_of_bytes_used);
-}
-
-static inline void RawBytesToDecimalBytes(const uint8_t* value, int32_t byte_width,
-                                          uint8_t* out_buf) {
-  // view the first 8 bytes as an unsigned 64-bit integer
-  auto low = reinterpret_cast<uint64_t*>(out_buf);
-
-  // view the second 8 bytes as a signed 64-bit integer
-  auto high = reinterpret_cast<int64_t*>(out_buf + sizeof(uint64_t));
-
-  // Convert the fixed size binary array bytes into a Decimal128 compatible layout
-  BytesToIntegerPair(value, byte_width, high, low);
-}
-
-/// \brief Convert an array of FixedLenByteArrays to an arrow::Decimal128Array
-/// We do this by:
-/// 1. Creating a arrow::FixedSizeBinaryArray from the RecordReader's builder
-/// 2. Allocating a buffer for the arrow::Decimal128Array
-/// 3. Converting the big-endian bytes in the FixedSizeBinaryArray to two integers
-///    representing the high and low bits of each decimal value.
-template <>
-struct TransferFunctor<::arrow::Decimal128Type, FLBAType> {
-  Status operator()(RecordReader* reader, MemoryPool* pool,
-                    const std::shared_ptr<::arrow::DataType>& type,
-                    std::shared_ptr<Array>* out) {
-    DCHECK_EQ(type->id(), ::arrow::Type::DECIMAL);
-
-    // Finish the built data into a temporary array
-    std::shared_ptr<Array> array;
-    RETURN_NOT_OK(reader->builder()->Finish(&array));
-    const auto& fixed_size_binary_array =
-        static_cast<const ::arrow::FixedSizeBinaryArray&>(*array);
-
-    // Get the byte width of the values in the FixedSizeBinaryArray. Most of the time
-    // this will be different from the decimal array width because we write the minimum
-    // number of bytes necessary to represent a given precision
-    const int32_t byte_width =
-        static_cast<const ::arrow::FixedSizeBinaryType&>(*fixed_size_binary_array.type())
-            .byte_width();
-
-    // The byte width of each decimal value
-    const int32_t type_length =
-        static_cast<const ::arrow::Decimal128Type&>(*type).byte_width();
-
-    // number of elements in the entire array
-    const int64_t length = fixed_size_binary_array.length();
-
-    // allocate memory for the decimal array
-    std::shared_ptr<Buffer> data;
-    RETURN_NOT_OK(::arrow::AllocateBuffer(pool, length * type_length, &data));
-
-    // raw bytes that we can write to
-    uint8_t* out_ptr = data->mutable_data();
-
-    // convert each FixedSizeBinary value to valid decimal bytes
-    const int64_t null_count = fixed_size_binary_array.null_count();
-    if (null_count > 0) {
-      for (int64_t i = 0; i < length; ++i, out_ptr += type_length) {
-        if (!fixed_size_binary_array.IsNull(i)) {
-          RawBytesToDecimalBytes(fixed_size_binary_array.GetValue(i), byte_width,
-                                 out_ptr);
-        }
-      }
-    } else {
-      for (int64_t i = 0; i < length; ++i, out_ptr += type_length) {
-        RawBytesToDecimalBytes(fixed_size_binary_array.GetValue(i), byte_width, out_ptr);
-      }
-    }
-
-    *out = std::make_shared<::arrow::Decimal128Array>(
-        type, length, data, fixed_size_binary_array.null_bitmap(), null_count);
-    return Status::OK();
-  }
-};
-
-/// \brief Convert an Int32 or Int64 array into a Decimal128Array
-/// The parquet spec allows systems to write decimals in int32, int64 if the values are
-/// small enough to fit in less 4 bytes or less than 8 bytes, respectively.
-/// This function implements the conversion from int32 and int64 arrays to decimal arrays.
-template <typename ParquetIntegerType,
-          typename = typename std::enable_if<
-              std::is_same<ParquetIntegerType, Int32Type>::value ||
-              std::is_same<ParquetIntegerType, Int64Type>::value>::type>
-static Status DecimalIntegerTransfer(RecordReader* reader, MemoryPool* pool,
-                                     const std::shared_ptr<::arrow::DataType>& type,
-                                     std::shared_ptr<Array>* out) {
-  DCHECK_EQ(type->id(), ::arrow::Type::DECIMAL);
-
-  const int64_t length = reader->values_written();
-
-  using ElementType = typename ParquetIntegerType::c_type;
-  static_assert(std::is_same<ElementType, int32_t>::value ||
-                    std::is_same<ElementType, int64_t>::value,
-                "ElementType must be int32_t or int64_t");
-
-  const auto values = reinterpret_cast<const ElementType*>(reader->values());
-
-  const auto& decimal_type = static_cast<const ::arrow::Decimal128Type&>(*type);
-  const int64_t type_length = decimal_type.byte_width();
-
-  std::shared_ptr<Buffer> data;
-  RETURN_NOT_OK(::arrow::AllocateBuffer(pool, length * type_length, &data));
-  uint8_t* out_ptr = data->mutable_data();
-
-  using ::arrow::BitUtil::FromLittleEndian;
-
-  for (int64_t i = 0; i < length; ++i, out_ptr += type_length) {
-    // sign/zero extend int32_t values, otherwise a no-op
-    const auto value = static_cast<int64_t>(values[i]);
-
-    auto out_ptr_view = reinterpret_cast<uint64_t*>(out_ptr);
-
-    // No-op on little endian machines, byteswap on big endian
-    out_ptr_view[0] = FromLittleEndian(static_cast<uint64_t>(value));
-
-    // no need to byteswap here because we're sign/zero extending exactly 8 bytes
-    out_ptr_view[1] = static_cast<uint64_t>(value < 0 ? -1 : 0);
-  }
-
-  if (reader->nullable_values()) {
-    std::shared_ptr<ResizableBuffer> is_valid = reader->ReleaseIsValid();
-    *out = std::make_shared<::arrow::Decimal128Array>(type, length, data, is_valid,
-                                                      reader->null_count());
-  } else {
-    *out = std::make_shared<::arrow::Decimal128Array>(type, length, data);
-  }
-  return Status::OK();
-}
-
-template <>
-struct TransferFunctor<::arrow::Decimal128Type, Int32Type> {
-  Status operator()(RecordReader* reader, MemoryPool* pool,
-                    const std::shared_ptr<::arrow::DataType>& type,
-                    std::shared_ptr<Array>* out) {
-    return DecimalIntegerTransfer<Int32Type>(reader, pool, type, out);
-  }
-};
-
-template <>
-struct TransferFunctor<::arrow::Decimal128Type, Int64Type> {
-  Status operator()(RecordReader* reader, MemoryPool* pool,
-                    const std::shared_ptr<::arrow::DataType>& type,
-                    std::shared_ptr<Array>* out) {
-    return DecimalIntegerTransfer<Int64Type>(reader, pool, type, out);
-  }
-};
-
-#define TRANSFER_DATA(ArrowType, ParquetType)                            \
-  TransferFunctor<ArrowType, ParquetType> func;                          \
-  RETURN_NOT_OK(func(record_reader_.get(), pool_, field_->type(), out)); \
-  RETURN_NOT_OK(WrapIntoListArray<ParquetType>(out))
-
-#define TRANSFER_CASE(ENUM, ArrowType, ParquetType) \
-  case ::arrow::Type::ENUM: {                       \
-    TRANSFER_DATA(ArrowType, ParquetType);          \
-  } break;
-
-Status PrimitiveImpl::NextBatch(int64_t records_to_read, std::shared_ptr<Array>* out) {
-  try {
-    // Pre-allocation gives much better performance for flat columns
-    record_reader_->Reserve(records_to_read);
-
-    record_reader_->Reset();
-    while (records_to_read > 0) {
-      if (!record_reader_->HasMoreData()) {
-        break;
-      }
-      int64_t records_read = record_reader_->ReadRecords(records_to_read);
-      records_to_read -= records_read;
-      if (records_read == 0) {
-        NextRowGroup();
-      }
-    }
-  } catch (const ::parquet::ParquetException& e) {
-    return ::arrow::Status::IOError(e.what());
-  }
-
-  switch (field_->type()->id()) {
-    TRANSFER_CASE(BOOL, ::arrow::BooleanType, BooleanType)
-    TRANSFER_CASE(UINT8, ::arrow::UInt8Type, Int32Type)
-    TRANSFER_CASE(INT8, ::arrow::Int8Type, Int32Type)
-    TRANSFER_CASE(UINT16, ::arrow::UInt16Type, Int32Type)
-    TRANSFER_CASE(INT16, ::arrow::Int16Type, Int32Type)
-    TRANSFER_CASE(UINT32, ::arrow::UInt32Type, Int32Type)
-    TRANSFER_CASE(INT32, ::arrow::Int32Type, Int32Type)
-    TRANSFER_CASE(UINT64, ::arrow::UInt64Type, Int64Type)
-    TRANSFER_CASE(INT64, ::arrow::Int64Type, Int64Type)
-    TRANSFER_CASE(FLOAT, ::arrow::FloatType, FloatType)
-    TRANSFER_CASE(DOUBLE, ::arrow::DoubleType, DoubleType)
-    TRANSFER_CASE(STRING, ::arrow::StringType, ByteArrayType)
-    TRANSFER_CASE(BINARY, ::arrow::BinaryType, ByteArrayType)
-    TRANSFER_CASE(DATE32, ::arrow::Date32Type, Int32Type)
-    TRANSFER_CASE(DATE64, ::arrow::Date64Type, Int32Type)
-    TRANSFER_CASE(FIXED_SIZE_BINARY, ::arrow::FixedSizeBinaryType, FLBAType)
-    case ::arrow::Type::NA: {
-      *out = std::make_shared<::arrow::NullArray>(record_reader_->values_written());
-      RETURN_NOT_OK(WrapIntoListArray<Int32Type>(out));
-      break;
-    }
-    case ::arrow::Type::DECIMAL: {
-      switch (descr_->physical_type()) {
-        case ::parquet::Type::INT32: {
-          TRANSFER_DATA(::arrow::Decimal128Type, Int32Type);
-        } break;
-        case ::parquet::Type::INT64: {
-          TRANSFER_DATA(::arrow::Decimal128Type, Int64Type);
-        } break;
-        case ::parquet::Type::FIXED_LEN_BYTE_ARRAY: {
-          TRANSFER_DATA(::arrow::Decimal128Type, FLBAType);
-        } break;
-        default:
-          return Status::Invalid(
-              "Physical type for decimal must be int32, int64, or fixed length binary");
-      }
-    } break;
-    case ::arrow::Type::TIMESTAMP: {
-      ::arrow::TimestampType* timestamp_type =
-          static_cast<::arrow::TimestampType*>(field_->type().get());
-      switch (timestamp_type->unit()) {
-        case ::arrow::TimeUnit::MILLI:
-        case ::arrow::TimeUnit::MICRO: {
-          TRANSFER_DATA(::arrow::TimestampType, Int64Type);
-        } break;
-        case ::arrow::TimeUnit::NANO: {
-          TRANSFER_DATA(::arrow::TimestampType, Int96Type);
-        } break;
-        default:
-          return Status::NotImplemented("TimeUnit not supported");
-      }
-    } break;
-      TRANSFER_CASE(TIME32, ::arrow::Time32Type, Int32Type)
-      TRANSFER_CASE(TIME64, ::arrow::Time64Type, Int64Type)
-    default:
-      std::stringstream ss;
-      ss << "No support for reading columns of type " << field_->type()->ToString();
-      return Status::NotImplemented(ss.str());
-  }
-
-  return Status::OK();
-}
-
-void PrimitiveImpl::NextRowGroup() {
-  std::unique_ptr<PageReader> page_reader = input_->NextChunk();
-  record_reader_->SetPageReader(std::move(page_reader));
-}
-
-Status PrimitiveImpl::GetDefLevels(const int16_t** data, size_t* length) {
-  *data = record_reader_->def_levels();
-  *length = record_reader_->levels_written();
-  return Status::OK();
-}
-
-Status PrimitiveImpl::GetRepLevels(const int16_t** data, size_t* length) {
-  *data = record_reader_->rep_levels();
-  *length = record_reader_->levels_written();
-  return Status::OK();
-}
-
-ColumnReader::ColumnReader(std::unique_ptr<ColumnReaderImpl> impl)
-    : impl_(std::move(impl)) {}
-
-ColumnReader::~ColumnReader() {}
-
-Status ColumnReader::NextBatch(int64_t records_to_read, std::shared_ptr<Array>* out) {
-  return impl_->NextBatch(records_to_read, out);
-}
-
-// StructImpl methods
-
-Status StructImpl::DefLevelsToNullArray(std::shared_ptr<Buffer>* null_bitmap_out,
-                                        int64_t* null_count_out) {
-  std::shared_ptr<Buffer> null_bitmap;
-  auto null_count = 0;
-  const int16_t* def_levels_data;
-  size_t def_levels_length;
-  RETURN_NOT_OK(GetDefLevels(&def_levels_data, &def_levels_length));
-  RETURN_NOT_OK(AllocateEmptyBitmap(pool_, def_levels_length, &null_bitmap));
-  uint8_t* null_bitmap_ptr = null_bitmap->mutable_data();
-  for (size_t i = 0; i < def_levels_length; i++) {
-    if (def_levels_data[i] < struct_def_level_) {
-      // Mark null
-      null_count += 1;
-    } else {
-      DCHECK_EQ(def_levels_data[i], struct_def_level_);
-      ::arrow::BitUtil::SetBit(null_bitmap_ptr, i);
-    }
-  }
-
-  *null_count_out = null_count;
-  *null_bitmap_out = (null_count == 0) ? nullptr : null_bitmap;
-  return Status::OK();
-}
-
-// TODO(itaiin): Consider caching the results of this calculation -
-//   note that this is only used once for each read for now
-Status StructImpl::GetDefLevels(const int16_t** data, size_t* length) {
-  *data = nullptr;
-  if (children_.size() == 0) {
-    // Empty struct
-    *length = 0;
-    return Status::OK();
-  }
-
-  // We have at least one child
-  const int16_t* child_def_levels;
-  size_t child_length;
-  RETURN_NOT_OK(children_[0]->GetDefLevels(&child_def_levels, &child_length));
-  auto size = child_length * sizeof(int16_t);
-  RETURN_NOT_OK(AllocateResizableBuffer(pool_, size, &def_levels_buffer_));
-  // Initialize with the minimal def level
-  std::memset(def_levels_buffer_->mutable_data(), -1, size);
-  auto result_levels = reinterpret_cast<int16_t*>(def_levels_buffer_->mutable_data());
-
-  // When a struct is defined, all of its children def levels are at least at
-  // nesting level, and def level equals nesting level.
-  // When a struct is not defined, all of its children def levels are less than
-  // the nesting level, and the def level equals max(children def levels)
-  // All other possibilities are malformed definition data.
-  for (auto& child : children_) {
-    size_t current_child_length;
-    RETURN_NOT_OK(child->GetDefLevels(&child_def_levels, &current_child_length));
-    DCHECK_EQ(child_length, current_child_length);
-    for (size_t i = 0; i < child_length; i++) {
-      // Check that value is either uninitialized, or current
-      // and previous children def levels agree on the struct level
-      DCHECK((result_levels[i] == -1) || ((result_levels[i] >= struct_def_level_) ==
-                                          (child_def_levels[i] >= struct_def_level_)));
-      result_levels[i] =
-          std::max(result_levels[i], std::min(child_def_levels[i], struct_def_level_));
-    }
-  }
-  *data = reinterpret_cast<const int16_t*>(def_levels_buffer_->data());
-  *length = child_length;
-  return Status::OK();
-}
-
-void StructImpl::InitField(
-    const Node* node, const std::vector<std::shared_ptr<ColumnReaderImpl>>& children) {
-  // Make a shallow node to field conversion from the children fields
-  std::vector<std::shared_ptr<::arrow::Field>> fields(children.size());
-  for (size_t i = 0; i < children.size(); i++) {
-    fields[i] = children[i]->field();
-  }
-  auto type = ::arrow::struct_(fields);
-  field_ = ::arrow::field(node->name(), type);
-}
-
-Status StructImpl::GetRepLevels(const int16_t** data, size_t* length) {
-  return Status::NotImplemented("GetRepLevels is not implemented for struct");
-}
-
-Status StructImpl::NextBatch(int64_t records_to_read, std::shared_ptr<Array>* out) {
-  std::vector<std::shared_ptr<Array>> children_arrays;
-  std::shared_ptr<Buffer> null_bitmap;
-  int64_t null_count;
-
-  // Gather children arrays and def levels
-  for (auto& child : children_) {
-    std::shared_ptr<Array> child_array;
-
-    RETURN_NOT_OK(child->NextBatch(records_to_read, &child_array));
-    children_arrays.push_back(child_array);
-  }
-
-  RETURN_NOT_OK(DefLevelsToNullArray(&null_bitmap, &null_count));
-
-  int64_t struct_length = children_arrays[0]->length();
-  for (size_t i = 1; i < children_arrays.size(); ++i) {
-    if (children_arrays[i]->length() != struct_length) {
-      // TODO(wesm): This should really only occur if the Parquet file is
-      // malformed. Should this be a DCHECK?
-      return Status::Invalid("Struct children had different lengths");
-    }
-  }
-
-  *out = std::make_shared<StructArray>(field()->type(), struct_length, children_arrays,
-                                       null_bitmap, null_count);
-  return Status::OK();
-}
-
-std::shared_ptr<ColumnChunkReader> RowGroupReader::Column(int column_index) {
-  return std::shared_ptr<ColumnChunkReader>(
-      new ColumnChunkReader(impl_, row_group_index_, column_index));
-}
-
-Status RowGroupReader::ReadTable(const std::vector<int>& column_indices,
-                                 std::shared_ptr<::arrow::Table>* out) {
-  return impl_->ReadRowGroup(row_group_index_, column_indices, out);
-}
-
-Status RowGroupReader::ReadTable(std::shared_ptr<::arrow::Table>* out) {
-  return impl_->ReadRowGroup(row_group_index_, out);
-}
-
-RowGroupReader::~RowGroupReader() {}
-
-RowGroupReader::RowGroupReader(FileReader::Impl* impl, int row_group_index)
-    : impl_(impl), row_group_index_(row_group_index) {}
-
-Status ColumnChunkReader::Read(std::shared_ptr<::arrow::Array>* out) {
-  return impl_->ReadColumnChunk(column_index_, row_group_index_, out);
-}
-
-ColumnChunkReader::~ColumnChunkReader() {}
-
-ColumnChunkReader::ColumnChunkReader(FileReader::Impl* impl, int row_group_index,
-                                     int column_index)
-    : impl_(impl), column_index_(column_index), row_group_index_(row_group_index) {}
-
-}  // namespace arrow
-}  // namespace parquet
diff --git a/src/parquet/arrow/reader.h b/src/parquet/arrow/reader.h
deleted file mode 100644
index db135da..0000000
--- a/src/parquet/arrow/reader.h
+++ /dev/null
@@ -1,306 +0,0 @@
-// 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.
-
-#ifndef PARQUET_ARROW_READER_H
-#define PARQUET_ARROW_READER_H
-
-#include <memory>
-#include <vector>
-
-#include "parquet/api/reader.h"
-#include "parquet/api/schema.h"
-
-#include "arrow/io/interfaces.h"
-
-namespace arrow {
-
-class Array;
-class MemoryPool;
-class RecordBatchReader;
-class Status;
-class Table;
-}  // namespace arrow
-
-namespace parquet {
-
-namespace arrow {
-
-class ColumnChunkReader;
-class ColumnReader;
-class RowGroupReader;
-
-// Arrow read adapter class for deserializing Parquet files as Arrow row
-// batches.
-//
-// This interfaces caters for different use cases and thus provides different
-// interfaces. In its most simplistic form, we cater for a user that wants to
-// read the whole Parquet at once with the FileReader::ReadTable method.
-//
-// More advanced users that also want to implement parallelism on top of each
-// single Parquet files should do this on the RowGroup level. For this, they can
-// call FileReader::RowGroup(i)->ReadTable to receive only the specified
-// RowGroup as a table.
-//
-// In the most advanced situation, where a consumer wants to independently read
-// RowGroups in parallel and consume each column individually, they can call
-// FileReader::RowGroup(i)->Column(j)->Read and receive an arrow::Column
-// instance.
-//
-// TODO(wesm): nested data does not always make sense with this user
-// interface unless you are only reading a single leaf node from a branch of
-// a table. For example:
-//
-// repeated group data {
-//   optional group record {
-//     optional int32 val1;
-//     optional byte_array val2;
-//     optional bool val3;
-//   }
-//   optional int32 val4;
-// }
-//
-// In the Parquet file, there are 3 leaf nodes:
-//
-// * data.record.val1
-// * data.record.val2
-// * data.record.val3
-// * data.val4
-//
-// When materializing this data in an Arrow array, we would have:
-//
-// data: list<struct<
-//   record: struct<
-//    val1: int32,
-//    val2: string (= list<uint8>),
-//    val3: bool,
-//   >,
-//   val4: int32
-// >>
-//
-// However, in the Parquet format, each leaf node has its own repetition and
-// definition levels describing the structure of the intermediate nodes in
-// this array structure. Thus, we will need to scan the leaf data for a group
-// of leaf nodes part of the same type tree to create a single result Arrow
-// nested array structure.
-//
-// This is additionally complicated "chunky" repeated fields or very large byte
-// arrays
-class PARQUET_EXPORT FileReader {
- public:
-  FileReader(::arrow::MemoryPool* pool, std::unique_ptr<ParquetFileReader> reader);
-
-  // Since the distribution of columns amongst a Parquet file's row groups may
-  // be uneven (the number of values in each column chunk can be different), we
-  // provide a column-oriented read interface. The ColumnReader hides the
-  // details of paging through the file's row groups and yielding
-  // fully-materialized arrow::Array instances
-  //
-  // Returns error status if the column of interest is not flat.
-  ::arrow::Status GetColumn(int i, std::unique_ptr<ColumnReader>* out);
-
-  /// \brief Return arrow schema by apply selection of column indices.
-  /// \returns error status if passed wrong indices.
-  ::arrow::Status GetSchema(const std::vector<int>& indices,
-                            std::shared_ptr<::arrow::Schema>* out);
-
-  // Read column as a whole into an Array.
-  ::arrow::Status ReadColumn(int i, std::shared_ptr<::arrow::Array>* out);
-
-  // NOTE: Experimental API
-  // Reads a specific top level schema field into an Array
-  // The index i refers the index of the top level schema field, which may
-  // be nested or flat - e.g.
-  //
-  // 0 foo.bar
-  //   foo.bar.baz
-  //   foo.qux
-  // 1 foo2
-  // 2 foo3
-  //
-  // i=0 will read the entire foo struct, i=1 the foo2 primitive column etc
-  ::arrow::Status ReadSchemaField(int i, std::shared_ptr<::arrow::Array>* out);
-
-  // NOTE: Experimental API
-  // Reads a specific top level schema field into an Array, while keeping only chosen
-  // leaf columns.
-  // The index i refers the index of the top level schema field, which may
-  // be nested or flat, and indices vector refers to the leaf column indices - e.g.
-  //
-  // i  indices
-  // 0  0        foo.bar
-  // 0  1        foo.bar.baz
-  // 0  2        foo.qux
-  // 1  3        foo2
-  // 2  4        foo3
-  //
-  // i=0 indices={0,2} will read a partial struct with foo.bar and foo.quox columns
-  // i=1 indices={3} will read foo2 column
-  // i=1 indices={2} will result in out=nullptr
-  // leaf indices which are unrelated to the schema field are ignored
-  ::arrow::Status ReadSchemaField(int i, const std::vector<int>& indices,
-                                  std::shared_ptr<::arrow::Array>* out);
-
-  /// \brief Return a RecordBatchReader of row groups selected from row_group_indices, the
-  ///    ordering in row_group_indices matters.
-  /// \returns error Status if row_group_indices contains invalid index
-  ::arrow::Status GetRecordBatchReader(const std::vector<int>& row_group_indices,
-                                       std::shared_ptr<::arrow::RecordBatchReader>* out);
-
-  /// \brief Return a RecordBatchReader of row groups selected from row_group_indices,
-  ///     whose columns are selected by column_indices. The ordering in row_group_indices
-  ///     and column_indices matter.
-  /// \returns error Status if either row_group_indices or column_indices contains invalid
-  ///    index
-  ::arrow::Status GetRecordBatchReader(const std::vector<int>& row_group_indices,
-                                       const std::vector<int>& column_indices,
-                                       std::shared_ptr<::arrow::RecordBatchReader>* out);
-
-  // Read a table of columns into a Table
-  ::arrow::Status ReadTable(std::shared_ptr<::arrow::Table>* out);
-
-  // Read a table of columns into a Table. Read only the indicated column
-  // indices (relative to the schema)
-  ::arrow::Status ReadTable(const std::vector<int>& column_indices,
-                            std::shared_ptr<::arrow::Table>* out);
-
-  ::arrow::Status ReadRowGroup(int i, const std::vector<int>& column_indices,
-                               std::shared_ptr<::arrow::Table>* out);
-
-  ::arrow::Status ReadRowGroup(int i, std::shared_ptr<::arrow::Table>* out);
-
-  ::arrow::Status ReadRowGroups(const std::vector<int>& row_groups,
-                                const std::vector<int>& column_indices,
-                                std::shared_ptr<::arrow::Table>* out);
-
-  ::arrow::Status ReadRowGroups(const std::vector<int>& row_groups,
-                                std::shared_ptr<::arrow::Table>* out);
-
-  /// \brief Scan file contents with one thread, return number of rows
-  ::arrow::Status ScanContents(std::vector<int> columns, const int32_t column_batch_size,
-                               int64_t* num_rows);
-
-  /// \brief Return a reader for the RowGroup, this object must not outlive the
-  ///   FileReader.
-  std::shared_ptr<RowGroupReader> RowGroup(int row_group_index);
-
-  int num_row_groups() const;
-
-  const ParquetFileReader* parquet_reader() const;
-
-  /// Set the number of threads to use during reads of multiple columns. By
-  /// default only 1 thread is used
-  /// \deprecated Use set_use_threads instead.
-  void set_num_threads(int num_threads);
-
-  /// Set whether to use multiple threads during reads of multiple columns.
-  /// By default only one thread is used.
-  void set_use_threads(bool use_threads);
-
-  virtual ~FileReader();
-
- private:
-  friend ColumnChunkReader;
-  friend RowGroupReader;
-
-  class PARQUET_NO_EXPORT Impl;
-  std::unique_ptr<Impl> impl_;
-};
-
-class PARQUET_EXPORT RowGroupReader {
- public:
-  std::shared_ptr<ColumnChunkReader> Column(int column_index);
-
-  ::arrow::Status ReadTable(const std::vector<int>& column_indices,
-                            std::shared_ptr<::arrow::Table>* out);
-  ::arrow::Status ReadTable(std::shared_ptr<::arrow::Table>* out);
-
-  virtual ~RowGroupReader();
-
- private:
-  friend FileReader;
-  RowGroupReader(FileReader::Impl* reader, int row_group_index);
-
-  FileReader::Impl* impl_;
-  int row_group_index_;
-};
-
-class PARQUET_EXPORT ColumnChunkReader {
- public:
-  ::arrow::Status Read(std::shared_ptr<::arrow::Array>* out);
-
-  virtual ~ColumnChunkReader();
-
- private:
-  friend RowGroupReader;
-  ColumnChunkReader(FileReader::Impl* impl, int row_group_index, int column_index);
-
-  FileReader::Impl* impl_;
-  int column_index_;
-  int row_group_index_;
-};
-
-// At this point, the column reader is a stream iterator. It only knows how to
-// read the next batch of values for a particular column from the file until it
-// runs out.
-//
-// We also do not expose any internal Parquet details, such as row groups. This
-// might change in the future.
-class PARQUET_EXPORT ColumnReader {
- public:
-  class PARQUET_NO_EXPORT ColumnReaderImpl;
-  virtual ~ColumnReader();
-
-  // Scan the next array of the indicated size. The actual size of the
-  // returned array may be less than the passed size depending how much data is
-  // available in the file.
-  //
-  // When all the data in the file has been exhausted, the result is set to
-  // nullptr.
-  //
-  // Returns Status::OK on a successful read, including if you have exhausted
-  // the data available in the file.
-  ::arrow::Status NextBatch(int64_t batch_size, std::shared_ptr<::arrow::Array>* out);
-
- private:
-  std::unique_ptr<ColumnReaderImpl> impl_;
-  explicit ColumnReader(std::unique_ptr<ColumnReaderImpl> impl);
-
-  friend class FileReader;
-  friend class PrimitiveImpl;
-  friend class StructImpl;
-};
-
-// Helper function to create a file reader from an implementation of an Arrow
-// readable file
-//
-// metadata : separately-computed file metadata, can be nullptr
-PARQUET_EXPORT
-::arrow::Status OpenFile(const std::shared_ptr<::arrow::io::ReadableFileInterface>& file,
-                         ::arrow::MemoryPool* allocator,
-                         const ReaderProperties& properties,
-                         const std::shared_ptr<FileMetaData>& metadata,
-                         std::unique_ptr<FileReader>* reader);
-
-PARQUET_EXPORT
-::arrow::Status OpenFile(const std::shared_ptr<::arrow::io::ReadableFileInterface>& file,
-                         ::arrow::MemoryPool* allocator,
-                         std::unique_ptr<FileReader>* reader);
-
-}  // namespace arrow
-}  // namespace parquet
-
-#endif  // PARQUET_ARROW_READER_H
diff --git a/src/parquet/arrow/record_reader.cc b/src/parquet/arrow/record_reader.cc
deleted file mode 100644
index 781e1ba..0000000
--- a/src/parquet/arrow/record_reader.cc
+++ /dev/null
@@ -1,817 +0,0 @@
-// 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.
-
-#include "parquet/arrow/record_reader.h"
-
-#include <algorithm>
-#include <cstdint>
-#include <memory>
-#include <sstream>
-
-#include <arrow/buffer.h>
-#include <arrow/memory_pool.h>
-#include <arrow/status.h>
-#include <arrow/util/bit-util.h>
-#include <arrow/util/rle-encoding.h>
-
-#include "parquet/column_page.h"
-#include "parquet/column_reader.h"
-#include "parquet/encoding-internal.h"
-#include "parquet/exception.h"
-#include "parquet/properties.h"
-
-using arrow::MemoryPool;
-
-namespace parquet {
-namespace internal {
-
-namespace BitUtil = ::arrow::BitUtil;
-
-template <typename DType>
-class TypedRecordReader;
-
-// PLAIN_DICTIONARY is deprecated but used to be used as a dictionary index
-// encoding.
-static bool IsDictionaryIndexEncoding(const Encoding::type& e) {
-  return e == Encoding::RLE_DICTIONARY || e == Encoding::PLAIN_DICTIONARY;
-}
-
-class RecordReader::RecordReaderImpl {
- public:
-  RecordReaderImpl(const ColumnDescriptor* descr, MemoryPool* pool)
-      : descr_(descr),
-        pool_(pool),
-        num_buffered_values_(0),
-        num_decoded_values_(0),
-        max_def_level_(descr->max_definition_level()),
-        max_rep_level_(descr->max_repetition_level()),
-        at_record_start_(true),
-        records_read_(0),
-        values_written_(0),
-        values_capacity_(0),
-        null_count_(0),
-        levels_written_(0),
-        levels_position_(0),
-        levels_capacity_(0) {
-    nullable_values_ = internal::HasSpacedValues(descr);
-    values_ = AllocateBuffer(pool);
-    valid_bits_ = AllocateBuffer(pool);
-    def_levels_ = AllocateBuffer(pool);
-    rep_levels_ = AllocateBuffer(pool);
-
-    if (descr->physical_type() == Type::BYTE_ARRAY) {
-      builder_.reset(new ::arrow::BinaryBuilder(pool));
-    } else if (descr->physical_type() == Type::FIXED_LEN_BYTE_ARRAY) {
-      int byte_width = descr->type_length();
-      std::shared_ptr<::arrow::DataType> type = ::arrow::fixed_size_binary(byte_width);
-      builder_.reset(new ::arrow::FixedSizeBinaryBuilder(type, pool));
-    }
-    Reset();
-  }
-
-  virtual ~RecordReaderImpl() = default;
-
-  virtual int64_t ReadRecords(int64_t num_records) = 0;
-
-  // Dictionary decoders must be reset when advancing row groups
-  virtual void ResetDecoders() = 0;
-
-  void SetPageReader(std::unique_ptr<PageReader> reader) {
-    at_record_start_ = true;
-    pager_ = std::move(reader);
-    ResetDecoders();
-  }
-
-  bool HasMoreData() const { return pager_ != nullptr; }
-
-  int16_t* def_levels() const {
-    return reinterpret_cast<int16_t*>(def_levels_->mutable_data());
-  }
-
-  int16_t* rep_levels() {
-    return reinterpret_cast<int16_t*>(rep_levels_->mutable_data());
-  }
-
-  uint8_t* values() const { return values_->mutable_data(); }
-
-  /// \brief Number of values written including nulls (if any)
-  int64_t values_written() const { return values_written_; }
-
-  int64_t levels_position() const { return levels_position_; }
-  int64_t levels_written() const { return levels_written_; }
-
-  // We may outwardly have the appearance of having exhausted a column chunk
-  // when in fact we are in the middle of processing the last batch
-  bool has_values_to_process() const { return levels_position_ < levels_written_; }
-
-  int64_t null_count() const { return null_count_; }
-
-  bool nullable_values() const { return nullable_values_; }
-
-  std::shared_ptr<ResizableBuffer> ReleaseValues() {
-    auto result = values_;
-    values_ = AllocateBuffer(pool_);
-    return result;
-  }
-
-  std::shared_ptr<ResizableBuffer> ReleaseIsValid() {
-    auto result = valid_bits_;
-    valid_bits_ = AllocateBuffer(pool_);
-    return result;
-  }
-
-  ::arrow::ArrayBuilder* builder() { return builder_.get(); }
-
-  // Process written repetition/definition levels to reach the end of
-  // records. Process no more levels than necessary to delimit the indicated
-  // number of logical records. Updates internal state of RecordReader
-  //
-  // \return Number of records delimited
-  int64_t DelimitRecords(int64_t num_records, int64_t* values_seen) {
-    int64_t values_to_read = 0;
-    int64_t records_read = 0;
-
-    const int16_t* def_levels = this->def_levels() + levels_position_;
-    const int16_t* rep_levels = this->rep_levels() + levels_position_;
-
-    DCHECK_GT(max_rep_level_, 0);
-
-    // Count logical records and number of values to read
-    while (levels_position_ < levels_written_) {
-      if (*rep_levels++ == 0) {
-        // If at_record_start_ is true, we are seeing the start of a record
-        // for the second time, such as after repeated calls to
-        // DelimitRecords. In this case we must continue until we find
-        // another record start or exhausting the ColumnChunk
-        if (!at_record_start_) {
-          // We've reached the end of a record; increment the record count.
-          ++records_read;
-          if (records_read == num_records) {
-            // We've found the number of records we were looking for. Set
-            // at_record_start_ to true and break
-            at_record_start_ = true;
-            break;
-          }
-        }
-      }
-
-      // We have decided to consume the level at this position; therefore we
-      // must advance until we find another record boundary
-      at_record_start_ = false;
-
-      if (*def_levels++ == max_def_level_) {
-        ++values_to_read;
-      }
-      ++levels_position_;
-    }
-    *values_seen = values_to_read;
-    return records_read;
-  }
-
-  // Read multiple definition levels into preallocated memory
-  //
-  // Returns the number of decoded definition levels
-  int64_t ReadDefinitionLevels(int64_t batch_size, int16_t* levels) {
-    if (descr_->max_definition_level() == 0) {
-      return 0;
-    }
-    return definition_level_decoder_.Decode(static_cast<int>(batch_size), levels);
-  }
-
-  int64_t ReadRepetitionLevels(int64_t batch_size, int16_t* levels) {
-    if (descr_->max_repetition_level() == 0) {
-      return 0;
-    }
-    return repetition_level_decoder_.Decode(static_cast<int>(batch_size), levels);
-  }
-
-  int64_t available_values_current_page() const {
-    return num_buffered_values_ - num_decoded_values_;
-  }
-
-  void ConsumeBufferedValues(int64_t num_values) { num_decoded_values_ += num_values; }
-
-  Type::type type() const { return descr_->physical_type(); }
-
-  const ColumnDescriptor* descr() const { return descr_; }
-
-  void Reserve(int64_t capacity) {
-    ReserveLevels(capacity);
-    ReserveValues(capacity);
-  }
-
-  void ReserveLevels(int64_t capacity) {
-    if (descr_->max_definition_level() > 0 &&
-        (levels_written_ + capacity > levels_capacity_)) {
-      int64_t new_levels_capacity = BitUtil::NextPower2(levels_capacity_ + 1);
-      while (levels_written_ + capacity > new_levels_capacity) {
-        new_levels_capacity = BitUtil::NextPower2(new_levels_capacity + 1);
-      }
-      PARQUET_THROW_NOT_OK(
-          def_levels_->Resize(new_levels_capacity * sizeof(int16_t), false));
-      if (descr_->max_repetition_level() > 0) {
-        PARQUET_THROW_NOT_OK(
-            rep_levels_->Resize(new_levels_capacity * sizeof(int16_t), false));
-      }
-      levels_capacity_ = new_levels_capacity;
-    }
-  }
-
-  void ReserveValues(int64_t capacity) {
-    if (values_written_ + capacity > values_capacity_) {
-      int64_t new_values_capacity = BitUtil::NextPower2(values_capacity_ + 1);
-      while (values_written_ + capacity > new_values_capacity) {
-        new_values_capacity = BitUtil::NextPower2(new_values_capacity + 1);
-      }
-
-      int type_size = GetTypeByteSize(descr_->physical_type());
-      PARQUET_THROW_NOT_OK(values_->Resize(new_values_capacity * type_size, false));
-      values_capacity_ = new_values_capacity;
-    }
-    if (nullable_values_) {
-      int64_t valid_bytes_new = BitUtil::BytesForBits(values_capacity_);
-      if (valid_bits_->size() < valid_bytes_new) {
-        int64_t valid_bytes_old = BitUtil::BytesForBits(values_written_);
-        PARQUET_THROW_NOT_OK(valid_bits_->Resize(valid_bytes_new, false));
-
-        // Avoid valgrind warnings
-        memset(valid_bits_->mutable_data() + valid_bytes_old, 0,
-               valid_bytes_new - valid_bytes_old);
-      }
-    }
-  }
-
-  void Reset() {
-    ResetValues();
-
-    if (levels_written_ > 0) {
-      const int64_t levels_remaining = levels_written_ - levels_position_;
-      // Shift remaining levels to beginning of buffer and trim to only the number
-      // of decoded levels remaining
-      int16_t* def_data = def_levels();
-      int16_t* rep_data = rep_levels();
-
-      std::copy(def_data + levels_position_, def_data + levels_written_, def_data);
-      std::copy(rep_data + levels_position_, rep_data + levels_written_, rep_data);
-
-      PARQUET_THROW_NOT_OK(
-          def_levels_->Resize(levels_remaining * sizeof(int16_t), false));
-      PARQUET_THROW_NOT_OK(
-          rep_levels_->Resize(levels_remaining * sizeof(int16_t), false));
-
-      levels_written_ -= levels_position_;
-      levels_position_ = 0;
-      levels_capacity_ = levels_remaining;
-    }
-
-    records_read_ = 0;
-
-    // Calling Finish on the builders also resets them
-  }
-
-  void ResetValues() {
-    if (values_written_ > 0) {
-      // Resize to 0, but do not shrink to fit
-      PARQUET_THROW_NOT_OK(values_->Resize(0, false));
-      PARQUET_THROW_NOT_OK(valid_bits_->Resize(0, false));
-      values_written_ = 0;
-      values_capacity_ = 0;
-      null_count_ = 0;
-    }
-  }
-
- protected:
-  const ColumnDescriptor* descr_;
-  ::arrow::MemoryPool* pool_;
-
-  std::unique_ptr<PageReader> pager_;
-  std::shared_ptr<Page> current_page_;
-
-  // Not set if full schema for this field has no optional or repeated elements
-  LevelDecoder definition_level_decoder_;
-
-  // Not set for flat schemas.
-  LevelDecoder repetition_level_decoder_;
-
-  // The total number of values stored in the data page. This is the maximum of
-  // the number of encoded definition levels or encoded values. For
-  // non-repeated, required columns, this is equal to the number of encoded
-  // values. For repeated or optional values, there may be fewer data values
-  // than levels, and this tells you how many encoded levels there are in that
-  // case.
-  int64_t num_buffered_values_;
-
-  // The number of values from the current data page that have been decoded
-  // into memory
-  int64_t num_decoded_values_;
-
-  const int16_t max_def_level_;
-  const int16_t max_rep_level_;
-
-  bool nullable_values_;
-
-  bool at_record_start_;
-  int64_t records_read_;
-
-  int64_t values_written_;
-  int64_t values_capacity_;
-  int64_t null_count_;
-
-  int64_t levels_written_;
-  int64_t levels_position_;
-  int64_t levels_capacity_;
-
-  // TODO(wesm): ByteArray / FixedLenByteArray types
-  std::unique_ptr<::arrow::ArrayBuilder> builder_;
-
-  std::shared_ptr<::arrow::ResizableBuffer> values_;
-
-  template <typename T>
-  T* ValuesHead() {
-    return reinterpret_cast<T*>(values_->mutable_data()) + values_written_;
-  }
-
-  std::shared_ptr<::arrow::ResizableBuffer> valid_bits_;
-  std::shared_ptr<::arrow::ResizableBuffer> def_levels_;
-  std::shared_ptr<::arrow::ResizableBuffer> rep_levels_;
-};
-
-// The minimum number of repetition/definition levels to decode at a time, for
-// better vectorized performance when doing many smaller record reads
-constexpr int64_t kMinLevelBatchSize = 1024;
-
-template <typename DType>
-class TypedRecordReader : public RecordReader::RecordReaderImpl {
- public:
-  typedef typename DType::c_type T;
-
-  TypedRecordReader(const ColumnDescriptor* schema, ::arrow::MemoryPool* pool)
-      : RecordReader::RecordReaderImpl(schema, pool), current_decoder_(nullptr) {}
-
-  void ResetDecoders() override { decoders_.clear(); }
-
-  inline void ReadValuesSpaced(int64_t values_with_nulls, int64_t null_count) {
-    uint8_t* valid_bits = valid_bits_->mutable_data();
-    const int64_t valid_bits_offset = values_written_;
-
-    int64_t num_decoded = current_decoder_->DecodeSpaced(
-        ValuesHead<T>(), static_cast<int>(values_with_nulls),
-        static_cast<int>(null_count), valid_bits, valid_bits_offset);
-    DCHECK_EQ(num_decoded, values_with_nulls);
-  }
-
-  inline void ReadValuesDense(int64_t values_to_read) {
-    int64_t num_decoded =
-        current_decoder_->Decode(ValuesHead<T>(), static_cast<int>(values_to_read));
-    DCHECK_EQ(num_decoded, values_to_read);
-  }
-
-  // Return number of logical records read
-  int64_t ReadRecordData(const int64_t num_records) {
-    // Conservative upper bound
-    const int64_t possible_num_values =
-        std::max(num_records, levels_written_ - levels_position_);
-    ReserveValues(possible_num_values);
-
-    const int64_t start_levels_position = levels_position_;
-
-    int64_t values_to_read = 0;
-    int64_t records_read = 0;
-    if (max_rep_level_ > 0) {
-      records_read = DelimitRecords(num_records, &values_to_read);
-    } else if (max_def_level_ > 0) {
-      // No repetition levels, skip delimiting logic. Each level represents a
-      // null or not null entry
-      records_read = std::min(levels_written_ - levels_position_, num_records);
-
-      // This is advanced by DelimitRecords, which we skipped
-      levels_position_ += records_read;
-    } else {
-      records_read = values_to_read = num_records;
-    }
-
-    int64_t null_count = 0;
-    if (nullable_values_) {
-      int64_t values_with_nulls = 0;
-      internal::DefinitionLevelsToBitmap(
-          def_levels() + start_levels_position, levels_position_ - start_levels_position,
-          max_def_level_, max_rep_level_, &values_with_nulls, &null_count,
-          valid_bits_->mutable_data(), values_written_);
-      values_to_read = values_with_nulls - null_count;
-      ReadValuesSpaced(values_with_nulls, null_count);
-      ConsumeBufferedValues(levels_position_ - start_levels_position);
-    } else {
-      ReadValuesDense(values_to_read);
-      ConsumeBufferedValues(values_to_read);
-    }
-    // Total values, including null spaces, if any
-    values_written_ += values_to_read + null_count;
-    null_count_ += null_count;
-
-    return records_read;
-  }
-
-  // Returns true if there are still values in this column.
-  bool HasNext() {
-    // Either there is no data page available yet, or the data page has been
-    // exhausted
-    if (num_buffered_values_ == 0 || num_decoded_values_ == num_buffered_values_) {
-      if (!ReadNewPage() || num_buffered_values_ == 0) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  int64_t ReadRecords(int64_t num_records) override {
-    // Delimit records, then read values at the end
-    int64_t records_read = 0;
-
-    if (levels_position_ < levels_written_) {
-      records_read += ReadRecordData(num_records);
-    }
-
-    int64_t level_batch_size = std::max(kMinLevelBatchSize, num_records);
-
-    // If we are in the middle of a record, we continue until reaching the
-    // desired number of records or the end of the current record if we've found
-    // enough records
-    while (!at_record_start_ || records_read < num_records) {
-      // Is there more data to read in this row group?
-      if (!HasNext()) {
-        if (!at_record_start_) {
-          // We ended the row group while inside a record that we haven't seen
-          // the end of yet. So increment the record count for the last record in
-          // the row group
-          ++records_read;
-          at_record_start_ = true;
-        }
-        break;
-      }
-
-      /// We perform multiple batch reads until we either exhaust the row group
-      /// or observe the desired number of records
-      int64_t batch_size = std::min(level_batch_size, available_values_current_page());
-
-      // No more data in column
-      if (batch_size == 0) {
-        break;
-      }
-
-      if (max_def_level_ > 0) {
-        ReserveLevels(batch_size);
-
-        int16_t* def_levels = this->def_levels() + levels_written_;
-        int16_t* rep_levels = this->rep_levels() + levels_written_;
-
-        // Not present for non-repeated fields
-        int64_t levels_read = 0;
-        if (max_rep_level_ > 0) {
-          levels_read = ReadDefinitionLevels(batch_size, def_levels);
-          if (ReadRepetitionLevels(batch_size, rep_levels) != levels_read) {
-            throw ParquetException("Number of decoded rep / def levels did not match");
-          }
-        } else if (max_def_level_ > 0) {
-          levels_read = ReadDefinitionLevels(batch_size, def_levels);
-        }
-
-        // Exhausted column chunk
-        if (levels_read == 0) {
-          break;
-        }
-
-        levels_written_ += levels_read;
-        records_read += ReadRecordData(num_records - records_read);
-      } else {
-        // No repetition or definition levels
-        batch_size = std::min(num_records - records_read, batch_size);
-        records_read += ReadRecordData(batch_size);
-      }
-    }
-
-    return records_read;
-  }
-
- private:
-  typedef Decoder<DType> DecoderType;
-
-  // Map of encoding type to the respective decoder object. For example, a
-  // column chunk's data pages may include both dictionary-encoded and
-  // plain-encoded data.
-  std::unordered_map<int, std::shared_ptr<DecoderType>> decoders_;
-
-  DecoderType* current_decoder_;
-
-  // Advance to the next data page
-  bool ReadNewPage();
-
-  void ConfigureDictionary(const DictionaryPage* page);
-};
-
-template <>
-inline void TypedRecordReader<ByteArrayType>::ReadValuesDense(int64_t values_to_read) {
-  auto values = ValuesHead<ByteArray>();
-  int64_t num_decoded =
-      current_decoder_->Decode(values, static_cast<int>(values_to_read));
-  DCHECK_EQ(num_decoded, values_to_read);
-
-  auto builder = static_cast<::arrow::BinaryBuilder*>(builder_.get());
-  for (int64_t i = 0; i < num_decoded; i++) {
-    PARQUET_THROW_NOT_OK(
-        builder->Append(values[i].ptr, static_cast<int64_t>(values[i].len)));
-  }
-  ResetValues();
-}
-
-template <>
-inline void TypedRecordReader<FLBAType>::ReadValuesDense(int64_t values_to_read) {
-  auto values = ValuesHead<FLBA>();
-  int64_t num_decoded =
-      current_decoder_->Decode(values, static_cast<int>(values_to_read));
-  DCHECK_EQ(num_decoded, values_to_read);
-
-  auto builder = static_cast<::arrow::FixedSizeBinaryBuilder*>(builder_.get());
-  for (int64_t i = 0; i < num_decoded; i++) {
-    PARQUET_THROW_NOT_OK(builder->Append(values[i].ptr));
-  }
-  ResetValues();
-}
-
-template <>
-inline void TypedRecordReader<ByteArrayType>::ReadValuesSpaced(int64_t values_to_read,
-                                                               int64_t null_count) {
-  uint8_t* valid_bits = valid_bits_->mutable_data();
-  const int64_t valid_bits_offset = values_written_;
-  auto values = ValuesHead<ByteArray>();
-
-  int64_t num_decoded = current_decoder_->DecodeSpaced(
-      values, static_cast<int>(values_to_read), static_cast<int>(null_count), valid_bits,
-      valid_bits_offset);
-  DCHECK_EQ(num_decoded, values_to_read);
-
-  auto builder = static_cast<::arrow::BinaryBuilder*>(builder_.get());
-
-  for (int64_t i = 0; i < num_decoded; i++) {
-    if (::arrow::BitUtil::GetBit(valid_bits, valid_bits_offset + i)) {
-      PARQUET_THROW_NOT_OK(
-          builder->Append(values[i].ptr, static_cast<int64_t>(values[i].len)));
-    } else {
-      PARQUET_THROW_NOT_OK(builder->AppendNull());
-    }
-  }
-  ResetValues();
-}
-
-template <>
-inline void TypedRecordReader<FLBAType>::ReadValuesSpaced(int64_t values_to_read,
-                                                          int64_t null_count) {
-  uint8_t* valid_bits = valid_bits_->mutable_data();
-  const int64_t valid_bits_offset = values_written_;
-  auto values = ValuesHead<FLBA>();
-
-  int64_t num_decoded = current_decoder_->DecodeSpaced(
-      values, static_cast<int>(values_to_read), static_cast<int>(null_count), valid_bits,
-      valid_bits_offset);
-  DCHECK_EQ(num_decoded, values_to_read);
-
-  auto builder = static_cast<::arrow::FixedSizeBinaryBuilder*>(builder_.get());
-  for (int64_t i = 0; i < num_decoded; i++) {
-    if (::arrow::BitUtil::GetBit(valid_bits, valid_bits_offset + i)) {
-      PARQUET_THROW_NOT_OK(builder->Append(values[i].ptr));
-    } else {
-      PARQUET_THROW_NOT_OK(builder->AppendNull());
-    }
-  }
-  ResetValues();
-}
-
-template <typename DType>
-inline void TypedRecordReader<DType>::ConfigureDictionary(const DictionaryPage* page) {
-  int encoding = static_cast<int>(page->encoding());
-  if (page->encoding() == Encoding::PLAIN_DICTIONARY ||
-      page->encoding() == Encoding::PLAIN) {
-    encoding = static_cast<int>(Encoding::RLE_DICTIONARY);
-  }
-
-  auto it = decoders_.find(encoding);
-  if (it != decoders_.end()) {
-    throw ParquetException("Column cannot have more than one dictionary.");
-  }
-
-  if (page->encoding() == Encoding::PLAIN_DICTIONARY ||
-      page->encoding() == Encoding::PLAIN) {
-    PlainDecoder<DType> dictionary(descr_);
-    dictionary.SetData(page->num_values(), page->data(), page->size());
-
-    // The dictionary is fully decoded during DictionaryDecoder::Init, so the
-    // DictionaryPage buffer is no longer required after this step
-    //
-    // TODO(wesm): investigate whether this all-or-nothing decoding of the
-    // dictionary makes sense and whether performance can be improved
-
-    auto decoder = std::make_shared<DictionaryDecoder<DType>>(descr_, pool_);
-    decoder->SetDict(&dictionary);
-    decoders_[encoding] = decoder;
-  } else {
-    ParquetException::NYI("only plain dictionary encoding has been implemented");
-  }
-
-  current_decoder_ = decoders_[encoding].get();
-}
-
-template <typename DType>
-bool TypedRecordReader<DType>::ReadNewPage() {
-  // Loop until we find the next data page.
-  const uint8_t* buffer;
-
-  while (true) {
-    current_page_ = pager_->NextPage();
-    if (!current_page_) {
-      // EOS
-      return false;
-    }
-
-    if (current_page_->type() == PageType::DICTIONARY_PAGE) {
-      ConfigureDictionary(static_cast<const DictionaryPage*>(current_page_.get()));
-      continue;
-    } else if (current_page_->type() == PageType::DATA_PAGE) {
-      const DataPage* page = static_cast<const DataPage*>(current_page_.get());
-
-      // Read a data page.
-      num_buffered_values_ = page->num_values();
-
-      // Have not decoded any values from the data page yet
-      num_decoded_values_ = 0;
-
-      buffer = page->data();
-
-      // If the data page includes repetition and definition levels, we
-      // initialize the level decoder and subtract the encoded level bytes from
-      // the page size to determine the number of bytes in the encoded data.
-      int64_t data_size = page->size();
-
-      // Data page Layout: Repetition Levels - Definition Levels - encoded values.
-      // Levels are encoded as rle or bit-packed.
-      // Init repetition levels
-      if (descr_->max_repetition_level() > 0) {
-        int64_t rep_levels_bytes = repetition_level_decoder_.SetData(
-            page->repetition_level_encoding(), descr_->max_repetition_level(),
-            static_cast<int>(num_buffered_values_), buffer);
-        buffer += rep_levels_bytes;
-        data_size -= rep_levels_bytes;
-      }
-      // TODO figure a way to set max_definition_level_ to 0
-      // if the initial value is invalid
-
-      // Init definition levels
-      if (descr_->max_definition_level() > 0) {
-        int64_t def_levels_bytes = definition_level_decoder_.SetData(
-            page->definition_level_encoding(), descr_->max_definition_level(),
-            static_cast<int>(num_buffered_values_), buffer);
-        buffer += def_levels_bytes;
-        data_size -= def_levels_bytes;
-      }
-
-      // Get a decoder object for this page or create a new decoder if this is the
-      // first page with this encoding.
-      Encoding::type encoding = page->encoding();
-
-      if (IsDictionaryIndexEncoding(encoding)) {
-        encoding = Encoding::RLE_DICTIONARY;
-      }
-
-      auto it = decoders_.find(static_cast<int>(encoding));
-      if (it != decoders_.end()) {
-        if (encoding == Encoding::RLE_DICTIONARY) {
-          DCHECK(current_decoder_->encoding() == Encoding::RLE_DICTIONARY);
-        }
-        current_decoder_ = it->second.get();
-      } else {
-        switch (encoding) {
-          case Encoding::PLAIN: {
-            std::shared_ptr<DecoderType> decoder(new PlainDecoder<DType>(descr_));
-            decoders_[static_cast<int>(encoding)] = decoder;
-            current_decoder_ = decoder.get();
-            break;
-          }
-          case Encoding::RLE_DICTIONARY:
-            throw ParquetException("Dictionary page must be before data page.");
-
-          case Encoding::DELTA_BINARY_PACKED:
-          case Encoding::DELTA_LENGTH_BYTE_ARRAY:
-          case Encoding::DELTA_BYTE_ARRAY:
-            ParquetException::NYI("Unsupported encoding");
-
-          default:
-            throw ParquetException("Unknown encoding type.");
-        }
-      }
-      current_decoder_->SetData(static_cast<int>(num_buffered_values_), buffer,
-                                static_cast<int>(data_size));
-      return true;
-    } else {
-      // We don't know what this page type is. We're allowed to skip non-data
-      // pages.
-      continue;
-    }
-  }
-  return true;
-}
-
-std::shared_ptr<RecordReader> RecordReader::Make(const ColumnDescriptor* descr,
-                                                 MemoryPool* pool) {
-  switch (descr->physical_type()) {
-    case Type::BOOLEAN:
-      return std::shared_ptr<RecordReader>(
-          new RecordReader(new TypedRecordReader<BooleanType>(descr, pool)));
-    case Type::INT32:
-      return std::shared_ptr<RecordReader>(
-          new RecordReader(new TypedRecordReader<Int32Type>(descr, pool)));
-    case Type::INT64:
-      return std::shared_ptr<RecordReader>(
-          new RecordReader(new TypedRecordReader<Int64Type>(descr, pool)));
-    case Type::INT96:
-      return std::shared_ptr<RecordReader>(
-          new RecordReader(new TypedRecordReader<Int96Type>(descr, pool)));
-    case Type::FLOAT:
-      return std::shared_ptr<RecordReader>(
-          new RecordReader(new TypedRecordReader<FloatType>(descr, pool)));
-    case Type::DOUBLE:
-      return std::shared_ptr<RecordReader>(
-          new RecordReader(new TypedRecordReader<DoubleType>(descr, pool)));
-    case Type::BYTE_ARRAY:
-      return std::shared_ptr<RecordReader>(
-          new RecordReader(new TypedRecordReader<ByteArrayType>(descr, pool)));
-    case Type::FIXED_LEN_BYTE_ARRAY:
-      return std::shared_ptr<RecordReader>(
-          new RecordReader(new TypedRecordReader<FLBAType>(descr, pool)));
-    default:
-      DCHECK(false);
-  }
-  // Unreachable code, but supress compiler warning
-  return nullptr;
-}
-
-// ----------------------------------------------------------------------
-// Implement public API
-
-RecordReader::RecordReader(RecordReaderImpl* impl) { impl_.reset(impl); }
-
-RecordReader::~RecordReader() {}
-
-int64_t RecordReader::ReadRecords(int64_t num_records) {
-  return impl_->ReadRecords(num_records);
-}
-
-void RecordReader::Reset() { return impl_->Reset(); }
-
-void RecordReader::Reserve(int64_t num_values) { impl_->Reserve(num_values); }
-
-const int16_t* RecordReader::def_levels() const { return impl_->def_levels(); }
-
-const int16_t* RecordReader::rep_levels() const { return impl_->rep_levels(); }
-
-const uint8_t* RecordReader::values() const { return impl_->values(); }
-
-std::shared_ptr<ResizableBuffer> RecordReader::ReleaseValues() {
-  return impl_->ReleaseValues();
-}
-
-std::shared_ptr<ResizableBuffer> RecordReader::ReleaseIsValid() {
-  return impl_->ReleaseIsValid();
-}
-
-::arrow::ArrayBuilder* RecordReader::builder() { return impl_->builder(); }
-
-int64_t RecordReader::values_written() const { return impl_->values_written(); }
-
-int64_t RecordReader::levels_position() const { return impl_->levels_position(); }
-
-int64_t RecordReader::levels_written() const { return impl_->levels_written(); }
-
-int64_t RecordReader::null_count() const { return impl_->null_count(); }
-
-bool RecordReader::nullable_values() const { return impl_->nullable_values(); }
-
-bool RecordReader::HasMoreData() const { return impl_->HasMoreData(); }
-
-void RecordReader::SetPageReader(std::unique_ptr<PageReader> reader) {
-  impl_->SetPageReader(std::move(reader));
-}
-
-}  // namespace internal
-}  // namespace parquet
diff --git a/src/parquet/arrow/record_reader.h b/src/parquet/arrow/record_reader.h
deleted file mode 100644
index f02bf05..0000000
--- a/src/parquet/arrow/record_reader.h
+++ /dev/null
@@ -1,113 +0,0 @@
-// 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.
-
-#ifndef PARQUET_RECORD_READER_H
-#define PARQUET_RECORD_READER_H
-
-#include <cstdint>
-#include <cstring>
-#include <iostream>
-#include <memory>
-#include <unordered_map>
-#include <vector>
-
-#include <arrow/buffer.h>
-#include <arrow/builder.h>
-#include <arrow/memory_pool.h>
-#include <arrow/util/bit-util.h>
-
-#include "parquet/column_reader.h"
-#include "parquet/schema.h"
-#include "parquet/util/visibility.h"
-
-namespace parquet {
-namespace internal {
-
-/// \brief Stateful column reader that delimits semantic records for both flat
-/// and nested columns
-///
-/// \note API EXPERIMENTAL
-/// \since 1.3.0
-class RecordReader {
- public:
-  // So that we can create subclasses
-  class RecordReaderImpl;
-
-  static std::shared_ptr<RecordReader> Make(
-      const ColumnDescriptor* descr,
-      ::arrow::MemoryPool* pool = ::arrow::default_memory_pool());
-
-  virtual ~RecordReader();
-
-  /// \brief Decoded definition levels
-  const int16_t* def_levels() const;
-
-  /// \brief Decoded repetition levels
-  const int16_t* rep_levels() const;
-
-  /// \brief Decoded values, including nulls, if any
-  const uint8_t* values() const;
-
-  /// \brief Attempt to read indicated number of records from column chunk
-  /// \return number of records read
-  int64_t ReadRecords(int64_t num_records);
-
-  /// \brief Pre-allocate space for data. Results in better flat read performance
-  void Reserve(int64_t num_values);
-
-  /// \brief Clear consumed values and repetition/definition levels as the
-  /// result of calling ReadRecords
-  void Reset();
-
-  std::shared_ptr<ResizableBuffer> ReleaseValues();
-  std::shared_ptr<ResizableBuffer> ReleaseIsValid();
-  ::arrow::ArrayBuilder* builder();
-
-  /// \brief Number of values written including nulls (if any)
-  int64_t values_written() const;
-
-  /// \brief Number of definition / repetition levels (from those that have
-  /// been decoded) that have been consumed inside the reader.
-  int64_t levels_position() const;
-
-  /// \brief Number of definition / repetition levels that have been written
-  /// internally in the reader
-  int64_t levels_written() const;
-
-  /// \brief Number of nulls in the leaf
-  int64_t null_count() const;
-
-  /// \brief True if the leaf values are nullable
-  bool nullable_values() const;
-
-  /// \brief Return true if the record reader has more internal data yet to
-  /// process
-  bool HasMoreData() const;
-
-  /// \brief Advance record reader to the next row group
-  /// \param[in] reader obtained from RowGroupReader::GetColumnPageReader
-  void SetPageReader(std::unique_ptr<PageReader> reader);
-
- private:
-  std::unique_ptr<RecordReaderImpl> impl_;
-  explicit RecordReader(RecordReaderImpl* impl);
-};
-
-}  // namespace internal
-}  // namespace parquet
-
-#endif  // PARQUET_RECORD_READER_H
diff --git a/src/parquet/arrow/schema.cc b/src/parquet/arrow/schema.cc
deleted file mode 100644
index 48b1181..0000000
--- a/src/parquet/arrow/schema.cc
+++ /dev/null
@@ -1,704 +0,0 @@
-// 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.
-
-#include "parquet/arrow/schema.h"
-
-#include <string>
-#include <unordered_set>
-#include <vector>
-
-#include "parquet/api/schema.h"
-#include "parquet/util/schema-util.h"
-
-#include "arrow/api.h"
-#include "arrow/util/logging.h"
-
-using arrow::Field;
-using arrow::Status;
-using arrow::TypePtr;
-
-using ArrowType = arrow::Type;
-
-using parquet::Repetition;
-using parquet::schema::GroupNode;
-using parquet::schema::Node;
-using parquet::schema::NodePtr;
-using parquet::schema::PrimitiveNode;
-
-using ParquetType = parquet::Type;
-using parquet::LogicalType;
-
-namespace parquet {
-
-namespace arrow {
-
-const auto TIMESTAMP_MS = ::arrow::timestamp(::arrow::TimeUnit::MILLI);
-const auto TIMESTAMP_US = ::arrow::timestamp(::arrow::TimeUnit::MICRO);
-const auto TIMESTAMP_NS = ::arrow::timestamp(::arrow::TimeUnit::NANO);
-
-TypePtr MakeDecimal128Type(const PrimitiveNode& node) {
-  const auto& metadata = node.decimal_metadata();
-  return ::arrow::decimal(metadata.precision, metadata.scale);
-}
-
-static Status FromByteArray(const PrimitiveNode& node, TypePtr* out) {
-  switch (node.logical_type()) {
-    case LogicalType::UTF8:
-      *out = ::arrow::utf8();
-      break;
-    case LogicalType::DECIMAL:
-      *out = MakeDecimal128Type(node);
-      break;
-    default:
-      // BINARY
-      *out = ::arrow::binary();
-      break;
-  }
-  return Status::OK();
-}
-
-static Status FromFLBA(const PrimitiveNode& node, TypePtr* out) {
-  switch (node.logical_type()) {
-    case LogicalType::NONE:
-      *out = ::arrow::fixed_size_binary(node.type_length());
-      break;
-    case LogicalType::DECIMAL:
-      *out = MakeDecimal128Type(node);
-      break;
-    default:
-      std::stringstream ss;
-      ss << "Unhandled logical type " << LogicalTypeToString(node.logical_type())
-         << " for fixed-length binary array";
-      return Status::NotImplemented(ss.str());
-  }
-
-  return Status::OK();
-}
-
-static Status FromInt32(const PrimitiveNode& node, TypePtr* out) {
-  switch (node.logical_type()) {
-    case LogicalType::NONE:
-      *out = ::arrow::int32();
-      break;
-    case LogicalType::UINT_8:
-      *out = ::arrow::uint8();
-      break;
-    case LogicalType::INT_8:
-      *out = ::arrow::int8();
-      break;
-    case LogicalType::UINT_16:
-      *out = ::arrow::uint16();
-      break;
-    case LogicalType::INT_16:
-      *out = ::arrow::int16();
-      break;
-    case LogicalType::INT_32:
-      *out = ::arrow::int32();
-      break;
-    case LogicalType::UINT_32:
-      *out = ::arrow::uint32();
-      break;
-    case LogicalType::DATE:
-      *out = ::arrow::date32();
-      break;
-    case LogicalType::TIME_MILLIS:
-      *out = ::arrow::time32(::arrow::TimeUnit::MILLI);
-      break;
-    case LogicalType::DECIMAL:
-      *out = MakeDecimal128Type(node);
-      break;
-    default:
-      std::stringstream ss;
-      ss << "Unhandled logical type " << LogicalTypeToString(node.logical_type())
-         << " for INT32";
-      return Status::NotImplemented(ss.str());
-  }
-  return Status::OK();
-}
-
-static Status FromInt64(const PrimitiveNode& node, TypePtr* out) {
-  switch (node.logical_type()) {
-    case LogicalType::NONE:
-      *out = ::arrow::int64();
-      break;
-    case LogicalType::INT_64:
-      *out = ::arrow::int64();
-      break;
-    case LogicalType::UINT_64:
-      *out = ::arrow::uint64();
-      break;
-    case LogicalType::DECIMAL:
-      *out = MakeDecimal128Type(node);
-      break;
-    case LogicalType::TIMESTAMP_MILLIS:
-      *out = TIMESTAMP_MS;
-      break;
-    case LogicalType::TIMESTAMP_MICROS:
-      *out = TIMESTAMP_US;
-      break;
-    case LogicalType::TIME_MICROS:
-      *out = ::arrow::time64(::arrow::TimeUnit::MICRO);
-      break;
-    default:
-      std::stringstream ss;
-      ss << "Unhandled logical type " << LogicalTypeToString(node.logical_type())
-         << " for INT64";
-      return Status::NotImplemented(ss.str());
-  }
-  return Status::OK();
-}
-
-Status FromPrimitive(const PrimitiveNode& primitive, TypePtr* out) {
-  if (primitive.logical_type() == LogicalType::NA) {
-    *out = ::arrow::null();
-    return Status::OK();
-  }
-
-  switch (primitive.physical_type()) {
-    case ParquetType::BOOLEAN:
-      *out = ::arrow::boolean();
-      break;
-    case ParquetType::INT32:
-      RETURN_NOT_OK(FromInt32(primitive, out));
-      break;
-    case ParquetType::INT64:
-      RETURN_NOT_OK(FromInt64(primitive, out));
-      break;
-    case ParquetType::INT96:
-      *out = TIMESTAMP_NS;
-      break;
-    case ParquetType::FLOAT:
-      *out = ::arrow::float32();
-      break;
-    case ParquetType::DOUBLE:
-      *out = ::arrow::float64();
-      break;
-    case ParquetType::BYTE_ARRAY:
-      RETURN_NOT_OK(FromByteArray(primitive, out));
-      break;
-    case ParquetType::FIXED_LEN_BYTE_ARRAY:
-      RETURN_NOT_OK(FromFLBA(primitive, out));
-      break;
-  }
-  return Status::OK();
-}
-
-// Forward declaration
-Status NodeToFieldInternal(const Node& node,
-                           const std::unordered_set<const Node*>* included_leaf_nodes,
-                           std::shared_ptr<Field>* out);
-
-/*
- * Auxilary function to test if a parquet schema node is a leaf node
- * that should be included in a resulting arrow schema
- */
-inline bool IsIncludedLeaf(const Node& node,
-                           const std::unordered_set<const Node*>* included_leaf_nodes) {
-  if (included_leaf_nodes == nullptr) {
-    return true;
-  }
-  auto search = included_leaf_nodes->find(&node);
-  return (search != included_leaf_nodes->end());
-}
-
-Status StructFromGroup(const GroupNode& group,
-                       const std::unordered_set<const Node*>* included_leaf_nodes,
-                       TypePtr* out) {
-  std::vector<std::shared_ptr<Field>> fields;
-  std::shared_ptr<Field> field;
-
-  *out = nullptr;
-
-  for (int i = 0; i < group.field_count(); i++) {
-    RETURN_NOT_OK(NodeToFieldInternal(*group.field(i), included_leaf_nodes, &field));
-    if (field != nullptr) {
-      fields.push_back(field);
-    }
-  }
-  if (fields.size() > 0) {
-    *out = std::make_shared<::arrow::StructType>(fields);
-  }
-  return Status::OK();
-}
-
-Status NodeToList(const GroupNode& group,
-                  const std::unordered_set<const Node*>* included_leaf_nodes,
-                  TypePtr* out) {
-  *out = nullptr;
-  if (group.field_count() == 1) {
-    // This attempts to resolve the preferred 3-level list encoding.
-    const Node& list_node = *group.field(0);
-    if (list_node.is_group() && list_node.is_repeated()) {
-      const auto& list_group = static_cast<const GroupNode&>(list_node);
-      // Special case mentioned in the format spec:
-      //   If the name is array or ends in _tuple, this should be a list of struct
-      //   even for single child elements.
-      if (list_group.field_count() == 1 && !HasStructListName(list_group)) {
-        // List of primitive type
-        std::shared_ptr<Field> item_field;
-        RETURN_NOT_OK(
-            NodeToFieldInternal(*list_group.field(0), included_leaf_nodes, &item_field));
-
-        if (item_field != nullptr) {
-          *out = ::arrow::list(item_field);
-        }
-      } else {
-        // List of struct
-        std::shared_ptr<::arrow::DataType> inner_type;
-        RETURN_NOT_OK(StructFromGroup(list_group, included_leaf_nodes, &inner_type));
-        if (inner_type != nullptr) {
-          auto item_field = std::make_shared<Field>(list_node.name(), inner_type, false);
-          *out = ::arrow::list(item_field);
-        }
-      }
-    } else if (list_node.is_repeated()) {
-      // repeated primitive node
-      std::shared_ptr<::arrow::DataType> inner_type;
-      if (IsIncludedLeaf(static_cast<const Node&>(list_node), included_leaf_nodes)) {
-        RETURN_NOT_OK(
-            FromPrimitive(static_cast<const PrimitiveNode&>(list_node), &inner_type));
-        auto item_field = std::make_shared<Field>(list_node.name(), inner_type, false);
-        *out = ::arrow::list(item_field);
-      }
-    } else {
-      return Status::NotImplemented(
-          "Non-repeated groups in a LIST-annotated group are not supported.");
-    }
-  } else {
-    return Status::NotImplemented(
-        "Only LIST-annotated groups with a single child can be handled.");
-  }
-  return Status::OK();
-}
-
-Status NodeToField(const Node& node, std::shared_ptr<Field>* out) {
-  return NodeToFieldInternal(node, nullptr, out);
-}
-
-Status NodeToFieldInternal(const Node& node,
-                           const std::unordered_set<const Node*>* included_leaf_nodes,
-                           std::shared_ptr<Field>* out) {
-  std::shared_ptr<::arrow::DataType> type = nullptr;
-  bool nullable = !node.is_required();
-
-  *out = nullptr;
-
-  if (node.is_repeated()) {
-    // 1-level LIST encoding fields are required
-    std::shared_ptr<::arrow::DataType> inner_type;
-    if (node.is_group()) {
-      RETURN_NOT_OK(StructFromGroup(static_cast<const GroupNode&>(node),
-                                    included_leaf_nodes, &inner_type));
-    } else if (IsIncludedLeaf(node, included_leaf_nodes)) {
-      RETURN_NOT_OK(FromPrimitive(static_cast<const PrimitiveNode&>(node), &inner_type));
-    }
-    if (inner_type != nullptr) {
-      auto item_field = std::make_shared<Field>(node.name(), inner_type, false);
-      type = ::arrow::list(item_field);
-      nullable = false;
-    }
-  } else if (node.is_group()) {
-    const auto& group = static_cast<const GroupNode&>(node);
-    if (node.logical_type() == LogicalType::LIST) {
-      RETURN_NOT_OK(NodeToList(group, included_leaf_nodes, &type));
-    } else {
-      RETURN_NOT_OK(StructFromGroup(group, included_leaf_nodes, &type));
-    }
-  } else {
-    // Primitive (leaf) node
-    if (IsIncludedLeaf(node, included_leaf_nodes)) {
-      RETURN_NOT_OK(FromPrimitive(static_cast<const PrimitiveNode&>(node), &type));
-    }
-  }
-  if (type != nullptr) {
-    *out = std::make_shared<Field>(node.name(), type, nullable);
-  }
-  return Status::OK();
-}
-
-Status FromParquetSchema(
-    const SchemaDescriptor* parquet_schema,
-    const std::shared_ptr<const KeyValueMetadata>& key_value_metadata,
-    std::shared_ptr<::arrow::Schema>* out) {
-  const GroupNode& schema_node = *parquet_schema->group_node();
-
-  int num_fields = static_cast<int>(schema_node.field_count());
-  std::vector<std::shared_ptr<Field>> fields(num_fields);
-  for (int i = 0; i < num_fields; i++) {
-    RETURN_NOT_OK(NodeToField(*schema_node.field(i), &fields[i]));
-  }
-
-  *out = std::make_shared<::arrow::Schema>(fields, key_value_metadata);
-  return Status::OK();
-}
-
-Status FromParquetSchema(
-    const SchemaDescriptor* parquet_schema, const std::vector<int>& column_indices,
-    const std::shared_ptr<const KeyValueMetadata>& key_value_metadata,
-    std::shared_ptr<::arrow::Schema>* out) {
-  // TODO(wesm): Consider adding an arrow::Schema name attribute, which comes
-  // from the root Parquet node
-
-  // Put the right leaf nodes in an unordered set
-  // Index in column_indices should be unique, duplicate indices are merged into one and
-  // ordering by its first appearing.
-  int num_columns = static_cast<int>(column_indices.size());
-  std::unordered_set<const Node*> top_nodes;  // to deduplicate the top nodes
-  std::vector<const Node*> base_nodes;        // to keep the ordering
-  std::unordered_set<const Node*> included_leaf_nodes(num_columns);
-  for (int i = 0; i < num_columns; i++) {
-    const ColumnDescriptor* column_desc = parquet_schema->Column(column_indices[i]);
-    included_leaf_nodes.insert(column_desc->schema_node().get());
-    const Node* column_root = parquet_schema->GetColumnRoot(column_indices[i]);
-    auto insertion = top_nodes.insert(column_root);
-    if (insertion.second) {
-      base_nodes.push_back(column_root);
-    }
-  }
-
-  std::vector<std::shared_ptr<Field>> fields;
-  std::shared_ptr<Field> field;
-  for (auto node : base_nodes) {
-    RETURN_NOT_OK(NodeToFieldInternal(*node, &included_leaf_nodes, &field));
-    if (field != nullptr) {
-      fields.push_back(field);
-    }
-  }
-
-  *out = std::make_shared<::arrow::Schema>(fields, key_value_metadata);
-  return Status::OK();
-}
-
-Status FromParquetSchema(const SchemaDescriptor* parquet_schema,
-                         const std::vector<int>& column_indices,
-                         std::shared_ptr<::arrow::Schema>* out) {
-  return FromParquetSchema(parquet_schema, column_indices, nullptr, out);
-}
-
-Status FromParquetSchema(const SchemaDescriptor* parquet_schema,
-                         std::shared_ptr<::arrow::Schema>* out) {
-  return FromParquetSchema(parquet_schema, nullptr, out);
-}
-
-Status ListToNode(const std::shared_ptr<::arrow::ListType>& type, const std::string& name,
-                  bool nullable, const WriterProperties& properties,
-                  const ArrowWriterProperties& arrow_properties, NodePtr* out) {
-  Repetition::type repetition = nullable ? Repetition::OPTIONAL : Repetition::REQUIRED;
-
-  NodePtr element;
-  RETURN_NOT_OK(FieldToNode(type->value_field(), properties, arrow_properties, &element));
-
-  NodePtr list = GroupNode::Make("list", Repetition::REPEATED, {element});
-  *out = GroupNode::Make(name, repetition, {list}, LogicalType::LIST);
-  return Status::OK();
-}
-
-Status StructToNode(const std::shared_ptr<::arrow::StructType>& type,
-                    const std::string& name, bool nullable,
-                    const WriterProperties& properties,
-                    const ArrowWriterProperties& arrow_properties, NodePtr* out) {
-  Repetition::type repetition = nullable ? Repetition::OPTIONAL : Repetition::REQUIRED;
-
-  std::vector<NodePtr> children(type->num_children());
-  for (int i = 0; i < type->num_children(); i++) {
-    RETURN_NOT_OK(
-        FieldToNode(type->child(i), properties, arrow_properties, &children[i]));
-  }
-
-  *out = GroupNode::Make(name, repetition, children);
-  return Status::OK();
-}
-
-static Status GetTimestampMetadata(const ::arrow::TimestampType& type,
-                                   const ArrowWriterProperties& properties,
-                                   ParquetType::type* physical_type,
-                                   LogicalType::type* logical_type) {
-  auto unit = type.unit();
-  *physical_type = ParquetType::INT64;
-
-  if (properties.coerce_timestamps_enabled()) {
-    auto coerce_unit = properties.coerce_timestamps_unit();
-    if (coerce_unit == ::arrow::TimeUnit::MILLI) {
-      *logical_type = LogicalType::TIMESTAMP_MILLIS;
-    } else if (coerce_unit == ::arrow::TimeUnit::MICRO) {
-      *logical_type = LogicalType::TIMESTAMP_MICROS;
-    } else {
-      return Status::NotImplemented(
-          "Can only coerce Arrow timestamps to milliseconds"
-          " or microseconds");
-    }
-    return Status::OK();
-  }
-
-  if (unit == ::arrow::TimeUnit::MILLI) {
-    *logical_type = LogicalType::TIMESTAMP_MILLIS;
-  } else if (unit == ::arrow::TimeUnit::MICRO) {
-    *logical_type = LogicalType::TIMESTAMP_MICROS;
-  } else if (unit == ::arrow::TimeUnit::NANO) {
-    if (properties.support_deprecated_int96_timestamps()) {
-      *physical_type = ParquetType::INT96;
-      // No corresponding logical type
-    } else {
-      *logical_type = LogicalType::TIMESTAMP_MICROS;
-    }
-  } else {
-    return Status::NotImplemented(
-        "Only MILLI, MICRO, and NANOS units supported for Arrow timestamps with "
-        "Parquet.");
-  }
-  return Status::OK();
-}
-
-Status FieldToNode(const std::shared_ptr<Field>& field,
-                   const WriterProperties& properties,
-                   const ArrowWriterProperties& arrow_properties, NodePtr* out) {
-  LogicalType::type logical_type = LogicalType::NONE;
-  ParquetType::type type;
-  Repetition::type repetition =
-      field->nullable() ? Repetition::OPTIONAL : Repetition::REQUIRED;
-
-  int length = -1;
-  int precision = -1;
-  int scale = -1;
-
-  switch (field->type()->id()) {
-    case ArrowType::NA:
-      type = ParquetType::INT32;
-      logical_type = LogicalType::NA;
-      break;
-    case ArrowType::BOOL:
-      type = ParquetType::BOOLEAN;
-      break;
-    case ArrowType::UINT8:
-      type = ParquetType::INT32;
-      logical_type = LogicalType::UINT_8;
-      break;
-    case ArrowType::INT8:
-      type = ParquetType::INT32;
-      logical_type = LogicalType::INT_8;
-      break;
-    case ArrowType::UINT16:
-      type = ParquetType::INT32;
-      logical_type = LogicalType::UINT_16;
-      break;
-    case ArrowType::INT16:
-      type = ParquetType::INT32;
-      logical_type = LogicalType::INT_16;
-      break;
-    case ArrowType::UINT32:
-      if (properties.version() == ::parquet::ParquetVersion::PARQUET_1_0) {
-        type = ParquetType::INT64;
-      } else {
-        type = ParquetType::INT32;
-        logical_type = LogicalType::UINT_32;
-      }
-      break;
-    case ArrowType::INT32:
-      type = ParquetType::INT32;
-      break;
-    case ArrowType::UINT64:
-      type = ParquetType::INT64;
-      logical_type = LogicalType::UINT_64;
-      break;
-    case ArrowType::INT64:
-      type = ParquetType::INT64;
-      break;
-    case ArrowType::FLOAT:
-      type = ParquetType::FLOAT;
-      break;
-    case ArrowType::DOUBLE:
-      type = ParquetType::DOUBLE;
-      break;
-    case ArrowType::STRING:
-      type = ParquetType::BYTE_ARRAY;
-      logical_type = LogicalType::UTF8;
-      break;
-    case ArrowType::BINARY:
-      type = ParquetType::BYTE_ARRAY;
-      break;
-    case ArrowType::FIXED_SIZE_BINARY: {
-      type = ParquetType::FIXED_LEN_BYTE_ARRAY;
-      const auto& fixed_size_binary_type =
-          static_cast<const ::arrow::FixedSizeBinaryType&>(*field->type());
-      length = fixed_size_binary_type.byte_width();
-    } break;
-    case ArrowType::DECIMAL: {
-      type = ParquetType::FIXED_LEN_BYTE_ARRAY;
-      logical_type = LogicalType::DECIMAL;
-      const auto& decimal_type =
-          static_cast<const ::arrow::Decimal128Type&>(*field->type());
-      precision = decimal_type.precision();
-      scale = decimal_type.scale();
-      length = DecimalSize(precision);
-    } break;
-    case ArrowType::DATE32:
-      type = ParquetType::INT32;
-      logical_type = LogicalType::DATE;
-      break;
-    case ArrowType::DATE64:
-      type = ParquetType::INT32;
-      logical_type = LogicalType::DATE;
-      break;
-    case ArrowType::TIMESTAMP:
-      RETURN_NOT_OK(
-          GetTimestampMetadata(static_cast<::arrow::TimestampType&>(*field->type()),
-                               arrow_properties, &type, &logical_type));
-      break;
-    case ArrowType::TIME32:
-      type = ParquetType::INT32;
-      logical_type = LogicalType::TIME_MILLIS;
-      break;
-    case ArrowType::TIME64: {
-      auto time_type = static_cast<::arrow::Time64Type*>(field->type().get());
-      if (time_type->unit() == ::arrow::TimeUnit::NANO) {
-        return Status::NotImplemented("Nanosecond time not supported in Parquet.");
-      }
-      type = ParquetType::INT64;
-      logical_type = LogicalType::TIME_MICROS;
-    } break;
-    case ArrowType::STRUCT: {
-      auto struct_type = std::static_pointer_cast<::arrow::StructType>(field->type());
-      return StructToNode(struct_type, field->name(), field->nullable(), properties,
-                          arrow_properties, out);
-    }
-    case ArrowType::LIST: {
-      auto list_type = std::static_pointer_cast<::arrow::ListType>(field->type());
-      return ListToNode(list_type, field->name(), field->nullable(), properties,
-                        arrow_properties, out);
-    }
-    case ArrowType::DICTIONARY: {
-      // Parquet has no Dictionary type, dictionary-encoded is handled on
-      // the encoding, not the schema level.
-      const ::arrow::DictionaryType& dict_type =
-          static_cast<const ::arrow::DictionaryType&>(*field->type());
-      std::shared_ptr<::arrow::Field> unpacked_field =
-          ::arrow::field(field->name(), dict_type.dictionary()->type(), field->nullable(),
-                         field->metadata());
-      return FieldToNode(unpacked_field, properties, arrow_properties, out);
-    }
-    default: {
-      // TODO: DENSE_UNION, SPARE_UNION, JSON_SCALAR, DECIMAL_TEXT, VARCHAR
-      std::stringstream ss;
-      ss << "Unhandled type for Arrow to Parquet schema conversion: ";
-      ss << field->type()->ToString();
-      return Status::NotImplemented(ss.str());
-    }
-  }
-  PARQUET_CATCH_NOT_OK(*out =
-                           PrimitiveNode::Make(field->name(), repetition, type,
-                                               logical_type, length, precision, scale));
-  return Status::OK();
-}
-
-Status ToParquetSchema(const ::arrow::Schema* arrow_schema,
-                       const WriterProperties& properties,
-                       const ArrowWriterProperties& arrow_properties,
-                       std::shared_ptr<SchemaDescriptor>* out) {
-  std::vector<NodePtr> nodes(arrow_schema->num_fields());
-  for (int i = 0; i < arrow_schema->num_fields(); i++) {
-    RETURN_NOT_OK(
-        FieldToNode(arrow_schema->field(i), properties, arrow_properties, &nodes[i]));
-  }
-
-  NodePtr schema = GroupNode::Make("schema", Repetition::REQUIRED, nodes);
-  *out = std::make_shared<::parquet::SchemaDescriptor>();
-  PARQUET_CATCH_NOT_OK((*out)->Init(schema));
-
-  return Status::OK();
-}
-
-Status ToParquetSchema(const ::arrow::Schema* arrow_schema,
-                       const WriterProperties& properties,
-                       std::shared_ptr<SchemaDescriptor>* out) {
-  return ToParquetSchema(arrow_schema, properties, *default_arrow_writer_properties(),
-                         out);
-}
-
-/// \brief Compute the number of bytes required to represent a decimal of a
-/// given precision. Taken from the Apache Impala codebase. The comments next
-/// to the return values are the maximum value that can be represented in 2's
-/// complement with the returned number of bytes.
-int32_t DecimalSize(int32_t precision) {
-  DCHECK_GE(precision, 1) << "decimal precision must be greater than or equal to 1, got "
-                          << precision;
-  DCHECK_LE(precision, 38) << "decimal precision must be less than or equal to 38, got "
-                           << precision;
-
-  switch (precision) {
-    case 1:
-    case 2:
-      return 1;  // 127
-    case 3:
-    case 4:
-      return 2;  // 32,767
-    case 5:
-    case 6:
-      return 3;  // 8,388,607
-    case 7:
-    case 8:
-    case 9:
-      return 4;  // 2,147,483,427
-    case 10:
-    case 11:
-      return 5;  // 549,755,813,887
-    case 12:
-    case 13:
-    case 14:
-      return 6;  // 140,737,488,355,327
-    case 15:
-    case 16:
-      return 7;  // 36,028,797,018,963,967
-    case 17:
-    case 18:
-      return 8;  // 9,223,372,036,854,775,807
-    case 19:
-    case 20:
-    case 21:
-      return 9;  // 2,361,183,241,434,822,606,847
-    case 22:
-    case 23:
-      return 10;  // 604,462,909,807,314,587,353,087
-    case 24:
-    case 25:
-    case 26:
-      return 11;  // 154,742,504,910,672,534,362,390,527
-    case 27:
-    case 28:
-      return 12;  // 39,614,081,257,132,168,796,771,975,167
-    case 29:
-    case 30:
-    case 31:
-      return 13;  // 10,141,204,801,825,835,211,973,625,643,007
-    case 32:
-    case 33:
-      return 14;  // 2,596,148,429,267,413,814,265,248,164,610,047
-    case 34:
-    case 35:
-      return 15;  // 664,613,997,892,457,936,451,903,530,140,172,287
-    case 36:
-    case 37:
-    case 38:
-      return 16;  // 170,141,183,460,469,231,731,687,303,715,884,105,727
-    default:
-      break;
-  }
-  DCHECK(false);
-  return -1;
-}
-
-}  // namespace arrow
-}  // namespace parquet
diff --git a/src/parquet/arrow/schema.h b/src/parquet/arrow/schema.h
deleted file mode 100644
index 3b212da..0000000
--- a/src/parquet/arrow/schema.h
+++ /dev/null
@@ -1,94 +0,0 @@
-// 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.
-
-#ifndef PARQUET_ARROW_SCHEMA_H
-#define PARQUET_ARROW_SCHEMA_H
-
-#include <memory>
-#include <vector>
-
-#include "arrow/api.h"
-
-#include "parquet/api/schema.h"
-#include "parquet/api/writer.h"
-#include "parquet/arrow/writer.h"
-
-namespace arrow {
-
-class Status;
-
-}  // namespace arrow
-
-namespace parquet {
-
-namespace arrow {
-
-PARQUET_EXPORT
-::arrow::Status NodeToField(const schema::Node& node,
-                            std::shared_ptr<::arrow::Field>* out);
-
-/// Convert parquet schema to arrow schema with selected indices
-/// \param parquet_schema to be converted
-/// \param column_indices indices of leaf nodes in parquet schema tree. Appearing ordering
-///                       matters for the converted schema. Repeated indices are ignored
-///                       except for the first one
-/// \param key_value_metadata optional metadata, can be nullptr
-/// \param out the corresponding arrow schema
-/// \return Status::OK() on a successful conversion.
-PARQUET_EXPORT
-::arrow::Status FromParquetSchema(
-    const SchemaDescriptor* parquet_schema, const std::vector<int>& column_indices,
-    const std::shared_ptr<const KeyValueMetadata>& key_value_metadata,
-    std::shared_ptr<::arrow::Schema>* out);
-
-// Without indices
-PARQUET_EXPORT
-::arrow::Status FromParquetSchema(
-    const SchemaDescriptor* parquet_schema,
-    const std::shared_ptr<const KeyValueMetadata>& key_value_metadata,
-    std::shared_ptr<::arrow::Schema>* out);
-
-// Without metadata
-::arrow::Status PARQUET_EXPORT FromParquetSchema(const SchemaDescriptor* parquet_schema,
-                                                 const std::vector<int>& column_indices,
-                                                 std::shared_ptr<::arrow::Schema>* out);
-
-// Without metadata or indices
-::arrow::Status PARQUET_EXPORT FromParquetSchema(const SchemaDescriptor* parquet_schema,
-                                                 std::shared_ptr<::arrow::Schema>* out);
-
-::arrow::Status PARQUET_EXPORT FieldToNode(const std::shared_ptr<::arrow::Field>& field,
-                                           const WriterProperties& properties,
-                                           const ArrowWriterProperties& arrow_properties,
-                                           schema::NodePtr* out);
-
-::arrow::Status PARQUET_EXPORT
-ToParquetSchema(const ::arrow::Schema* arrow_schema, const WriterProperties& properties,
-                const ArrowWriterProperties& arrow_properties,
-                std::shared_ptr<SchemaDescriptor>* out);
-
-::arrow::Status PARQUET_EXPORT ToParquetSchema(const ::arrow::Schema* arrow_schema,
-                                               const WriterProperties& properties,
-                                               std::shared_ptr<SchemaDescriptor>* out);
-
-int32_t DecimalSize(int32_t precision);
-
-}  // namespace arrow
-
-}  // namespace parquet
-
-#endif  // PARQUET_ARROW_SCHEMA_H
diff --git a/src/parquet/arrow/test-util.h b/src/parquet/arrow/test-util.h
deleted file mode 100644
index 631bb71..0000000
--- a/src/parquet/arrow/test-util.h
+++ /dev/null
@@ -1,525 +0,0 @@
-// 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.
-
-#include <limits>
-#include <string>
-#include <vector>
-
-#include "arrow/api.h"
-#include "arrow/test-util.h"
-#include "arrow/type_traits.h"
-#include "arrow/util/decimal.h"
-
-#include "parquet/arrow/record_reader.h"
-
-namespace arrow {
-// PARQUET-1382: backwards-compatible shim for arrow::test namespace
-namespace test {}
-
-using namespace ::arrow::test;  // NOLINT
-
-}  // namespace arrow
-
-namespace parquet {
-
-using internal::RecordReader;
-
-namespace arrow {
-
-using ::arrow::Array;
-using ::arrow::Status;
-
-template <int32_t PRECISION>
-struct DecimalWithPrecisionAndScale {
-  static_assert(PRECISION >= 1 && PRECISION <= 38, "Invalid precision value");
-
-  using type = ::arrow::Decimal128Type;
-  static constexpr ::arrow::Type::type type_id = ::arrow::Decimal128Type::type_id;
-  static constexpr int32_t precision = PRECISION;
-  static constexpr int32_t scale = PRECISION - 1;
-};
-
-template <typename ArrowType>
-using is_arrow_float = std::is_floating_point<typename ArrowType::c_type>;
-
-template <typename ArrowType>
-using is_arrow_int = std::is_integral<typename ArrowType::c_type>;
-
-template <typename ArrowType>
-using is_arrow_date = std::is_same<ArrowType, ::arrow::Date64Type>;
-
-template <typename ArrowType>
-using is_arrow_string = std::is_same<ArrowType, ::arrow::StringType>;
-
-template <typename ArrowType>
-using is_arrow_binary = std::is_same<ArrowType, ::arrow::BinaryType>;
-
-template <typename ArrowType>
-using is_arrow_fixed_size_binary = std::is_same<ArrowType, ::arrow::FixedSizeBinaryType>;
-
-template <typename ArrowType>
-using is_arrow_bool = std::is_same<ArrowType, ::arrow::BooleanType>;
-
-template <class ArrowType>
-typename std::enable_if<is_arrow_float<ArrowType>::value, Status>::type NonNullArray(
-    size_t size, std::shared_ptr<Array>* out) {
-  using c_type = typename ArrowType::c_type;
-  std::vector<c_type> values;
-  ::arrow::random_real(size, 0, static_cast<c_type>(0), static_cast<c_type>(1), &values);
-  ::arrow::NumericBuilder<ArrowType> builder;
-  RETURN_NOT_OK(builder.AppendValues(values.data(), values.size()));
-  return builder.Finish(out);
-}
-
-template <class ArrowType>
-typename std::enable_if<
-    is_arrow_int<ArrowType>::value && !is_arrow_date<ArrowType>::value, Status>::type
-NonNullArray(size_t size, std::shared_ptr<Array>* out) {
-  std::vector<typename ArrowType::c_type> values;
-  ::arrow::randint(size, 0, 64, &values);
-
-  // Passing data type so this will work with TimestampType too
-  ::arrow::NumericBuilder<ArrowType> builder(std::make_shared<ArrowType>(),
-                                             ::arrow::default_memory_pool());
-  RETURN_NOT_OK(builder.AppendValues(values.data(), values.size()));
-  return builder.Finish(out);
-}
-
-template <class ArrowType>
-typename std::enable_if<is_arrow_date<ArrowType>::value, Status>::type NonNullArray(
-    size_t size, std::shared_ptr<Array>* out) {
-  std::vector<typename ArrowType::c_type> values;
-  ::arrow::randint(size, 0, 64, &values);
-  for (size_t i = 0; i < size; i++) {
-    values[i] *= 86400000;
-  }
-
-  // Passing data type so this will work with TimestampType too
-  ::arrow::NumericBuilder<ArrowType> builder(std::make_shared<ArrowType>(),
-                                             ::arrow::default_memory_pool());
-  builder.AppendValues(values.data(), values.size());
-  return builder.Finish(out);
-}
-
-template <class ArrowType>
-typename std::enable_if<
-    is_arrow_string<ArrowType>::value || is_arrow_binary<ArrowType>::value, Status>::type
-NonNullArray(size_t size, std::shared_ptr<Array>* out) {
-  using BuilderType = typename ::arrow::TypeTraits<ArrowType>::BuilderType;
-  BuilderType builder;
-  for (size_t i = 0; i < size; i++) {
-    RETURN_NOT_OK(builder.Append("test-string"));
-  }
-  return builder.Finish(out);
-}
-
-template <typename ArrowType>
-typename std::enable_if<is_arrow_fixed_size_binary<ArrowType>::value, Status>::type
-NonNullArray(size_t size, std::shared_ptr<Array>* out) {
-  using BuilderType = typename ::arrow::TypeTraits<ArrowType>::BuilderType;
-  // set byte_width to the length of "fixed": 5
-  // todo: find a way to generate test data with more diversity.
-  BuilderType builder(::arrow::fixed_size_binary(5));
-  for (size_t i = 0; i < size; i++) {
-    RETURN_NOT_OK(builder.Append("fixed"));
-  }
-  return builder.Finish(out);
-}
-
-static inline void random_decimals(int64_t n, uint32_t seed, int32_t precision,
-                                   uint8_t* out) {
-  std::mt19937 gen(seed);
-  std::uniform_int_distribution<uint32_t> d(0, std::numeric_limits<uint8_t>::max());
-  const int32_t required_bytes = DecimalSize(precision);
-  constexpr int32_t byte_width = 16;
-  std::fill(out, out + byte_width * n, '\0');
-
-  for (int64_t i = 0; i < n; ++i, out += byte_width) {
-    std::generate(out, out + required_bytes,
-                  [&d, &gen] { return static_cast<uint8_t>(d(gen)); });
-
-    // sign extend if the sign bit is set for the last byte generated
-    // 0b10000000 == 0x80 == 128
-    if ((out[required_bytes - 1] & '\x80') != 0) {
-      std::fill(out + required_bytes, out + byte_width, '\xFF');
-    }
-  }
-}
-
-template <typename ArrowType, int32_t precision = ArrowType::precision>
-typename std::enable_if<
-    std::is_same<ArrowType, DecimalWithPrecisionAndScale<precision>>::value, Status>::type
-NonNullArray(size_t size, std::shared_ptr<Array>* out) {
-  constexpr int32_t kDecimalPrecision = precision;
-  constexpr int32_t kDecimalScale = DecimalWithPrecisionAndScale<precision>::scale;
-
-  const auto type = ::arrow::decimal(kDecimalPrecision, kDecimalScale);
-  ::arrow::Decimal128Builder builder(type);
-  const int32_t byte_width =
-      static_cast<const ::arrow::Decimal128Type&>(*type).byte_width();
-
-  constexpr int32_t seed = 0;
-
-  std::shared_ptr<Buffer> out_buf;
-  RETURN_NOT_OK(::arrow::AllocateBuffer(::arrow::default_memory_pool(), size * byte_width,
-                                        &out_buf));
-  random_decimals(size, seed, kDecimalPrecision, out_buf->mutable_data());
-
-  RETURN_NOT_OK(builder.AppendValues(out_buf->data(), size));
-  return builder.Finish(out);
-}
-
-template <class ArrowType>
-typename std::enable_if<is_arrow_bool<ArrowType>::value, Status>::type NonNullArray(
-    size_t size, std::shared_ptr<Array>* out) {
-  std::vector<uint8_t> values;
-  ::arrow::randint(size, 0, 1, &values);
-  ::arrow::BooleanBuilder builder;
-  RETURN_NOT_OK(builder.AppendValues(values.data(), values.size()));
-  return builder.Finish(out);
-}
-
-// This helper function only supports (size/2) nulls.
-template <typename ArrowType>
-typename std::enable_if<is_arrow_float<ArrowType>::value, Status>::type NullableArray(
-    size_t size, size_t num_nulls, uint32_t seed, std::shared_ptr<Array>* out) {
-  using c_type = typename ArrowType::c_type;
-  std::vector<c_type> values;
-  ::arrow::random_real(size, seed, static_cast<c_type>(-1e10), static_cast<c_type>(1e10),
-                       &values);
-  std::vector<uint8_t> valid_bytes(size, 1);
-
-  for (size_t i = 0; i < num_nulls; i++) {
-    valid_bytes[i * 2] = 0;
-  }
-
-  ::arrow::NumericBuilder<ArrowType> builder;
-  RETURN_NOT_OK(builder.AppendValues(values.data(), values.size(), valid_bytes.data()));
-  return builder.Finish(out);
-}
-
-// This helper function only supports (size/2) nulls.
-template <typename ArrowType>
-typename std::enable_if<
-    is_arrow_int<ArrowType>::value && !is_arrow_date<ArrowType>::value, Status>::type
-NullableArray(size_t size, size_t num_nulls, uint32_t seed, std::shared_ptr<Array>* out) {
-  std::vector<typename ArrowType::c_type> values;
-
-  // Seed is random in Arrow right now
-  (void)seed;
-  ::arrow::randint(size, 0, 64, &values);
-  std::vector<uint8_t> valid_bytes(size, 1);
-
-  for (size_t i = 0; i < num_nulls; i++) {
-    valid_bytes[i * 2] = 0;
-  }
-
-  // Passing data type so this will work with TimestampType too
-  ::arrow::NumericBuilder<ArrowType> builder(std::make_shared<ArrowType>(),
-                                             ::arrow::default_memory_pool());
-  RETURN_NOT_OK(builder.AppendValues(values.data(), values.size(), valid_bytes.data()));
-  return builder.Finish(out);
-}
-
-template <typename ArrowType>
-typename std::enable_if<is_arrow_date<ArrowType>::value, Status>::type NullableArray(
-    size_t size, size_t num_nulls, uint32_t seed, std::shared_ptr<Array>* out) {
-  std::vector<typename ArrowType::c_type> values;
-
-  // Seed is random in Arrow right now
-  (void)seed;
-  ::arrow::randint(size, 0, 64, &values);
-  for (size_t i = 0; i < size; i++) {
-    values[i] *= 86400000;
-  }
-  std::vector<uint8_t> valid_bytes(size, 1);
-
-  for (size_t i = 0; i < num_nulls; i++) {
-    valid_bytes[i * 2] = 0;
-  }
-
-  // Passing data type so this will work with TimestampType too
-  ::arrow::NumericBuilder<ArrowType> builder(std::make_shared<ArrowType>(),
-                                             ::arrow::default_memory_pool());
-  builder.AppendValues(values.data(), values.size(), valid_bytes.data());
-  return builder.Finish(out);
-}
-
-// This helper function only supports (size/2) nulls yet.
-template <typename ArrowType>
-typename std::enable_if<
-    is_arrow_string<ArrowType>::value || is_arrow_binary<ArrowType>::value, Status>::type
-NullableArray(size_t size, size_t num_nulls, uint32_t seed,
-              std::shared_ptr<::arrow::Array>* out) {
-  std::vector<uint8_t> valid_bytes(size, 1);
-
-  for (size_t i = 0; i < num_nulls; i++) {
-    valid_bytes[i * 2] = 0;
-  }
-
-  using BuilderType = typename ::arrow::TypeTraits<ArrowType>::BuilderType;
-  BuilderType builder;
-
-  const int kBufferSize = 10;
-  uint8_t buffer[kBufferSize];
-  for (size_t i = 0; i < size; i++) {
-    if (!valid_bytes[i]) {
-      RETURN_NOT_OK(builder.AppendNull());
-    } else {
-      ::arrow::random_bytes(kBufferSize, seed + static_cast<uint32_t>(i), buffer);
-      RETURN_NOT_OK(builder.Append(buffer, kBufferSize));
-    }
-  }
-  return builder.Finish(out);
-}
-
-// This helper function only supports (size/2) nulls yet,
-// same as NullableArray<String|Binary>(..)
-template <typename ArrowType>
-typename std::enable_if<is_arrow_fixed_size_binary<ArrowType>::value, Status>::type
-NullableArray(size_t size, size_t num_nulls, uint32_t seed,
-              std::shared_ptr<::arrow::Array>* out) {
-  std::vector<uint8_t> valid_bytes(size, 1);
-
-  for (size_t i = 0; i < num_nulls; i++) {
-    valid_bytes[i * 2] = 0;
-  }
-
-  using BuilderType = typename ::arrow::TypeTraits<ArrowType>::BuilderType;
-  const int byte_width = 10;
-  BuilderType builder(::arrow::fixed_size_binary(byte_width));
-
-  const int kBufferSize = byte_width;
-  uint8_t buffer[kBufferSize];
-  for (size_t i = 0; i < size; i++) {
-    if (!valid_bytes[i]) {
-      RETURN_NOT_OK(builder.AppendNull());
-    } else {
-      ::arrow::random_bytes(kBufferSize, seed + static_cast<uint32_t>(i), buffer);
-      RETURN_NOT_OK(builder.Append(buffer));
-    }
-  }
-  return builder.Finish(out);
-}
-
-template <typename ArrowType, int32_t precision = ArrowType::precision>
-typename std::enable_if<
-    std::is_same<ArrowType, DecimalWithPrecisionAndScale<precision>>::value, Status>::type
-NullableArray(size_t size, size_t num_nulls, uint32_t seed,
-              std::shared_ptr<::arrow::Array>* out) {
-  std::vector<uint8_t> valid_bytes(size, '\1');
-
-  for (size_t i = 0; i < num_nulls; ++i) {
-    valid_bytes[i * 2] = '\0';
-  }
-
-  constexpr int32_t kDecimalPrecision = precision;
-  constexpr int32_t kDecimalScale = DecimalWithPrecisionAndScale<precision>::scale;
-  const auto type = ::arrow::decimal(kDecimalPrecision, kDecimalScale);
-  const int32_t byte_width =
-      static_cast<const ::arrow::Decimal128Type&>(*type).byte_width();
-
-  std::shared_ptr<::arrow::Buffer> out_buf;
-  RETURN_NOT_OK(::arrow::AllocateBuffer(::arrow::default_memory_pool(), size * byte_width,
-                                        &out_buf));
-
-  random_decimals(size, seed, precision, out_buf->mutable_data());
-
-  ::arrow::Decimal128Builder builder(type);
-  RETURN_NOT_OK(builder.AppendValues(out_buf->data(), size, valid_bytes.data()));
-  return builder.Finish(out);
-}
-
-// This helper function only supports (size/2) nulls yet.
-template <class ArrowType>
-typename std::enable_if<is_arrow_bool<ArrowType>::value, Status>::type NullableArray(
-    size_t size, size_t num_nulls, uint32_t seed, std::shared_ptr<Array>* out) {
-  std::vector<uint8_t> values;
-
-  // Seed is random in Arrow right now
-  (void)seed;
-
-  ::arrow::randint(size, 0, 1, &values);
-  std::vector<uint8_t> valid_bytes(size, 1);
-
-  for (size_t i = 0; i < num_nulls; i++) {
-    valid_bytes[i * 2] = 0;
-  }
-
-  ::arrow::BooleanBuilder builder;
-  RETURN_NOT_OK(builder.AppendValues(values.data(), values.size(), valid_bytes.data()));
-  return builder.Finish(out);
-}
-
-/// Wrap an Array into a ListArray by splitting it up into size lists.
-///
-/// This helper function only supports (size/2) nulls.
-Status MakeListArray(const std::shared_ptr<Array>& values, int64_t size,
-                     int64_t null_count, bool nullable_values,
-                     std::shared_ptr<::arrow::ListArray>* out) {
-  // We always include an empty list
-  int64_t non_null_entries = size - null_count - 1;
-  int64_t length_per_entry = values->length() / non_null_entries;
-
-  auto offsets = AllocateBuffer();
-  RETURN_NOT_OK(offsets->Resize((size + 1) * sizeof(int32_t)));
-  int32_t* offsets_ptr = reinterpret_cast<int32_t*>(offsets->mutable_data());
-
-  auto null_bitmap = AllocateBuffer();
-  int64_t bitmap_size = ::arrow::BitUtil::BytesForBits(size);
-  RETURN_NOT_OK(null_bitmap->Resize(bitmap_size));
-  uint8_t* null_bitmap_ptr = null_bitmap->mutable_data();
-  memset(null_bitmap_ptr, 0, bitmap_size);
-
-  int32_t current_offset = 0;
-  for (int64_t i = 0; i < size; i++) {
-    offsets_ptr[i] = current_offset;
-    if (!(((i % 2) == 0) && ((i / 2) < null_count))) {
-      // Non-null list (list with index 1 is always empty).
-      ::arrow::BitUtil::SetBit(null_bitmap_ptr, i);
-      if (i != 1) {
-        current_offset += static_cast<int32_t>(length_per_entry);
-      }
-    }
-  }
-  offsets_ptr[size] = static_cast<int32_t>(values->length());
-
-  auto value_field = ::arrow::field("item", values->type(), nullable_values);
-  *out = std::make_shared<::arrow::ListArray>(::arrow::list(value_field), size, offsets,
-                                              values, null_bitmap, null_count);
-
-  return Status::OK();
-}
-
-// Make an array containing only empty lists, with a null values array
-Status MakeEmptyListsArray(int64_t size, std::shared_ptr<Array>* out_array) {
-  // Allocate an offsets buffer containing only zeroes
-  std::shared_ptr<Buffer> offsets_buffer;
-  const int64_t offsets_nbytes = (size + 1) * sizeof(int32_t);
-  RETURN_NOT_OK(::arrow::AllocateBuffer(::arrow::default_memory_pool(), offsets_nbytes,
-                                        &offsets_buffer));
-  memset(offsets_buffer->mutable_data(), 0, offsets_nbytes);
-
-  auto value_field =
-      ::arrow::field("item", ::arrow::float64(), false /* nullable_values */);
-  auto list_type = ::arrow::list(value_field);
-
-  std::vector<std::shared_ptr<Buffer>> child_buffers = {nullptr /* null bitmap */,
-                                                        nullptr /* values */};
-  auto child_data =
-      ::arrow::ArrayData::Make(value_field->type(), 0, std::move(child_buffers));
-
-  std::vector<std::shared_ptr<Buffer>> buffers = {nullptr /* bitmap */, offsets_buffer};
-  auto array_data = ::arrow::ArrayData::Make(list_type, size, std::move(buffers));
-  array_data->child_data.push_back(child_data);
-
-  *out_array = ::arrow::MakeArray(array_data);
-  return Status::OK();
-}
-
-static std::shared_ptr<::arrow::Column> MakeColumn(const std::string& name,
-                                                   const std::shared_ptr<Array>& array,
-                                                   bool nullable) {
-  auto field = ::arrow::field(name, array->type(), nullable);
-  return std::make_shared<::arrow::Column>(field, array);
-}
-
-static std::shared_ptr<::arrow::Column> MakeColumn(
-    const std::string& name, const std::vector<std::shared_ptr<Array>>& arrays,
-    bool nullable) {
-  auto field = ::arrow::field(name, arrays[0]->type(), nullable);
-  return std::make_shared<::arrow::Column>(field, arrays);
-}
-
-std::shared_ptr<::arrow::Table> MakeSimpleTable(const std::shared_ptr<Array>& values,
-                                                bool nullable) {
-  std::shared_ptr<::arrow::Column> column = MakeColumn("col", values, nullable);
-  std::vector<std::shared_ptr<::arrow::Column>> columns({column});
-  std::vector<std::shared_ptr<::arrow::Field>> fields({column->field()});
-  auto schema = std::make_shared<::arrow::Schema>(fields);
-  return ::arrow::Table::Make(schema, columns);
-}
-
-template <typename T>
-void ExpectArray(T* expected, Array* result) {
-  auto p_array = static_cast<::arrow::PrimitiveArray*>(result);
-  for (int i = 0; i < result->length(); i++) {
-    EXPECT_EQ(expected[i], reinterpret_cast<const T*>(p_array->values()->data())[i]);
-  }
-}
-
-template <typename ArrowType>
-void ExpectArrayT(void* expected, Array* result) {
-  ::arrow::PrimitiveArray* p_array = static_cast<::arrow::PrimitiveArray*>(result);
-  for (int64_t i = 0; i < result->length(); i++) {
-    EXPECT_EQ(reinterpret_cast<typename ArrowType::c_type*>(expected)[i],
-              reinterpret_cast<const typename ArrowType::c_type*>(
-                  p_array->values()->data())[i]);
-  }
-}
-
-template <>
-void ExpectArrayT<::arrow::BooleanType>(void* expected, Array* result) {
-  ::arrow::BooleanBuilder builder;
-  EXPECT_OK(builder.AppendValues(reinterpret_cast<uint8_t*>(expected), result->length()));
-
-  std::shared_ptr<Array> expected_array;
-  EXPECT_OK(builder.Finish(&expected_array));
-  EXPECT_TRUE(result->Equals(*expected_array));
-}
-
-template <typename ParquetType>
-void PrintBufferedLevels(const RecordReader& reader) {
-  using T = typename ::parquet::type_traits<ParquetType::type_num>::value_type;
-
-  const int16_t* def_levels = reader.def_levels();
-  const int16_t* rep_levels = reader.rep_levels();
-  const int64_t total_levels_read = reader.levels_position();
-
-  const T* values = reinterpret_cast<const T*>(reader.values());
-
-  std::cout << "def levels: ";
-  for (int64_t i = 0; i < total_levels_read; ++i) {
-    std::cout << def_levels[i] << " ";
-  }
-  std::cout << std::endl;
-
-  std::cout << "rep levels: ";
-  for (int64_t i = 0; i < total_levels_read; ++i) {
-    std::cout << rep_levels[i] << " ";
-  }
-  std::cout << std::endl;
-
-  std::cout << "values: ";
-  for (int64_t i = 0; i < reader.values_written(); ++i) {
-    std::cout << values[i] << " ";
-  }
-  std::cout << std::endl;
-}
-
-template <>
-void PrintBufferedLevels<ByteArrayType>(const RecordReader& reader) {}
-
-template <>
-void PrintBufferedLevels<FLBAType>(const RecordReader& reader) {}
-
-template <>
-void PrintBufferedLevels<Int96Type>(const RecordReader& reader) {}
-
-}  // namespace arrow
-
-}  // namespace parquet
diff --git a/src/parquet/arrow/writer.cc b/src/parquet/arrow/writer.cc
deleted file mode 100644
index b7d139e..0000000
--- a/src/parquet/arrow/writer.cc
+++ /dev/null
@@ -1,1151 +0,0 @@
-// 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.
-
-#include "parquet/arrow/writer.h"
-
-#include <algorithm>
-#include <string>
-#include <vector>
-
-#include "arrow/api.h"
-#include "arrow/compute/api.h"
-#include "arrow/util/bit-util.h"
-#include "arrow/visitor_inline.h"
-
-#include "parquet/arrow/schema.h"
-#include "parquet/util/logging.h"
-
-using arrow::Array;
-using arrow::BinaryArray;
-using arrow::BooleanArray;
-using arrow::ChunkedArray;
-using arrow::Decimal128Array;
-using arrow::Field;
-using arrow::FixedSizeBinaryArray;
-using arrow::Int16Array;
-using arrow::Int16Builder;
-using arrow::ListArray;
-using arrow::MemoryPool;
-using arrow::NumericArray;
-using arrow::PrimitiveArray;
-using arrow::ResizableBuffer;
-using arrow::Status;
-using arrow::Table;
-using arrow::TimeUnit;
-
-using arrow::compute::Cast;
-using arrow::compute::CastOptions;
-using arrow::compute::FunctionContext;
-
-using parquet::ParquetFileWriter;
-using parquet::ParquetVersion;
-using parquet::schema::GroupNode;
-
-namespace parquet {
-namespace arrow {
-
-namespace BitUtil = ::arrow::BitUtil;
-
-std::shared_ptr<ArrowWriterProperties> default_arrow_writer_properties() {
-  static std::shared_ptr<ArrowWriterProperties> default_writer_properties =
-      ArrowWriterProperties::Builder().build();
-  return default_writer_properties;
-}
-
-namespace {
-
-class LevelBuilder {
- public:
-  explicit LevelBuilder(MemoryPool* pool)
-      : def_levels_(::arrow::int16(), pool), rep_levels_(::arrow::int16(), pool) {}
-
-  Status VisitInline(const Array& array);
-
-  template <typename T>
-  typename std::enable_if<std::is_base_of<::arrow::FlatArray, T>::value, Status>::type
-  Visit(const T& array) {
-    array_offsets_.push_back(static_cast<int32_t>(array.offset()));
-    valid_bitmaps_.push_back(array.null_bitmap_data());
-    null_counts_.push_back(array.null_count());
-    values_array_ = std::make_shared<T>(array.data());
-    return Status::OK();
-  }
-
-  Status Visit(const ListArray& array) {
-    array_offsets_.push_back(static_cast<int32_t>(array.offset()));
-    valid_bitmaps_.push_back(array.null_bitmap_data());
-    null_counts_.push_back(array.null_count());
-    offsets_.push_back(array.raw_value_offsets());
-
-    min_offset_idx_ = array.value_offset(min_offset_idx_);
-    max_offset_idx_ = array.value_offset(max_offset_idx_);
-
-    return VisitInline(*array.values());
-  }
-
-#define NOT_IMPLEMENTED_VISIT(ArrowTypePrefix)                             \
-  Status Visit(const ::arrow::ArrowTypePrefix##Array& array) {             \
-    return Status::NotImplemented("Level generation for " #ArrowTypePrefix \
-                                  " not supported yet");                   \
-  }
-
-  NOT_IMPLEMENTED_VISIT(Struct)
-  NOT_IMPLEMENTED_VISIT(Union)
-  NOT_IMPLEMENTED_VISIT(Dictionary)
-
-  Status GenerateLevels(const Array& array, const std::shared_ptr<Field>& field,
-                        int64_t* values_offset, int64_t* num_values, int64_t* num_levels,
-                        const std::shared_ptr<ResizableBuffer>& def_levels_scratch,
-                        std::shared_ptr<Buffer>* def_levels_out,
-                        std::shared_ptr<Buffer>* rep_levels_out,
-                        std::shared_ptr<Array>* values_array) {
-    // Work downwards to extract bitmaps and offsets
-    min_offset_idx_ = 0;
-    max_offset_idx_ = array.length();
-    RETURN_NOT_OK(VisitInline(array));
-    *num_values = max_offset_idx_ - min_offset_idx_;
-    *values_offset = min_offset_idx_;
-    *values_array = values_array_;
-
-    // Walk downwards to extract nullability
-    std::shared_ptr<Field> current_field = field;
-    nullable_.push_back(current_field->nullable());
-    while (current_field->type()->num_children() > 0) {
-      if (current_field->type()->num_children() > 1) {
-        return Status::NotImplemented(
-            "Fields with more than one child are not supported.");
-      } else {
-        current_field = current_field->type()->child(0);
-      }
-      nullable_.push_back(current_field->nullable());
-    }
-
-    // Generate the levels.
-    if (nullable_.size() == 1) {
-      // We have a PrimitiveArray
-      *rep_levels_out = nullptr;
-      if (nullable_[0]) {
-        RETURN_NOT_OK(
-            def_levels_scratch->Resize(array.length() * sizeof(int16_t), false));
-        auto def_levels_ptr =
-            reinterpret_cast<int16_t*>(def_levels_scratch->mutable_data());
-        if (array.null_count() == 0) {
-          std::fill(def_levels_ptr, def_levels_ptr + array.length(), 1);
-        } else if (array.null_count() == array.length()) {
-          std::fill(def_levels_ptr, def_levels_ptr + array.length(), 0);
-        } else {
-          ::arrow::internal::BitmapReader valid_bits_reader(
-              array.null_bitmap_data(), array.offset(), array.length());
-          for (int i = 0; i < array.length(); i++) {
-            def_levels_ptr[i] = valid_bits_reader.IsSet() ? 1 : 0;
-            valid_bits_reader.Next();
-          }
-        }
-
-        *def_levels_out = def_levels_scratch;
-      } else {
-        *def_levels_out = nullptr;
-      }
-      *num_levels = array.length();
-    } else {
-      RETURN_NOT_OK(rep_levels_.Append(0));
-      RETURN_NOT_OK(HandleListEntries(0, 0, 0, array.length()));
-
-      std::shared_ptr<Array> def_levels_array;
-      std::shared_ptr<Array> rep_levels_array;
-
-      RETURN_NOT_OK(def_levels_.Finish(&def_levels_array));
-      RETURN_NOT_OK(rep_levels_.Finish(&rep_levels_array));
-
-      *def_levels_out = static_cast<PrimitiveArray*>(def_levels_array.get())->values();
-      *rep_levels_out = static_cast<PrimitiveArray*>(rep_levels_array.get())->values();
-      *num_levels = rep_levels_array->length();
-    }
-
-    return Status::OK();
-  }
-
-  Status HandleList(int16_t def_level, int16_t rep_level, int64_t index) {
-    if (nullable_[rep_level]) {
-      if (null_counts_[rep_level] == 0 ||
-          BitUtil::GetBit(valid_bitmaps_[rep_level], index + array_offsets_[rep_level])) {
-        return HandleNonNullList(static_cast<int16_t>(def_level + 1), rep_level, index);
-      } else {
-        return def_levels_.Append(def_level);
-      }
-    } else {
-      return HandleNonNullList(def_level, rep_level, index);
-    }
-  }
-
-  Status HandleNonNullList(int16_t def_level, int16_t rep_level, int64_t index) {
-    const int32_t inner_offset = offsets_[rep_level][index];
-    const int32_t inner_length = offsets_[rep_level][index + 1] - inner_offset;
-    const int64_t recursion_level = rep_level + 1;
-    if (inner_length == 0) {
-      return def_levels_.Append(def_level);
-    }
-    if (recursion_level < static_cast<int64_t>(offsets_.size())) {
-      return HandleListEntries(static_cast<int16_t>(def_level + 1),
-                               static_cast<int16_t>(rep_level + 1), inner_offset,
-                               inner_length);
-    } else {
-      // We have reached the leaf: primitive list, handle remaining nullables
-      const bool nullable_level = nullable_[recursion_level];
-      const int64_t level_null_count = null_counts_[recursion_level];
-      const uint8_t* level_valid_bitmap = valid_bitmaps_[recursion_level];
-
-      for (int64_t i = 0; i < inner_length; i++) {
-        if (i > 0) {
-          RETURN_NOT_OK(rep_levels_.Append(static_cast<int16_t>(rep_level + 1)));
-        }
-        if (level_null_count && level_valid_bitmap == nullptr) {
-          // Special case: this is a null array (all elements are null)
-          RETURN_NOT_OK(def_levels_.Append(static_cast<int16_t>(def_level + 1)));
-        } else if (nullable_level &&
-                   ((level_null_count == 0) ||
-                    BitUtil::GetBit(
-                        level_valid_bitmap,
-                        inner_offset + i + array_offsets_[recursion_level]))) {
-          // Non-null element in a null level
-          RETURN_NOT_OK(def_levels_.Append(static_cast<int16_t>(def_level + 2)));
-        } else {
-          // This can be produced in two case:
-          //  * elements are nullable and this one is null (i.e. max_def_level = def_level
-          //  + 2)
-          //  * elements are non-nullable (i.e. max_def_level = def_level + 1)
-          RETURN_NOT_OK(def_levels_.Append(static_cast<int16_t>(def_level + 1)));
-        }
-      }
-      return Status::OK();
-    }
-  }
-
-  Status HandleListEntries(int16_t def_level, int16_t rep_level, int64_t offset,
-                           int64_t length) {
-    for (int64_t i = 0; i < length; i++) {
-      if (i > 0) {
-        RETURN_NOT_OK(rep_levels_.Append(rep_level));
-      }
-      RETURN_NOT_OK(HandleList(def_level, rep_level, offset + i));
-    }
-    return Status::OK();
-  }
-
- private:
-  Int16Builder def_levels_;
-  Int16Builder rep_levels_;
-
-  std::vector<int64_t> null_counts_;
-  std::vector<const uint8_t*> valid_bitmaps_;
-  std::vector<const int32_t*> offsets_;
-  std::vector<int32_t> array_offsets_;
-  std::vector<bool> nullable_;
-
-  int64_t min_offset_idx_;
-  int64_t max_offset_idx_;
-  std::shared_ptr<Array> values_array_;
-};
-
-Status LevelBuilder::VisitInline(const Array& array) {
-  return VisitArrayInline(array, this);
-}
-
-struct ColumnWriterContext {
-  ColumnWriterContext(MemoryPool* memory_pool, ArrowWriterProperties* properties)
-      : memory_pool(memory_pool), properties(properties) {
-    this->data_buffer = AllocateBuffer(memory_pool);
-    this->def_levels_buffer = AllocateBuffer(memory_pool);
-  }
-
-  template <typename T>
-  Status GetScratchData(const int64_t num_values, T** out) {
-    RETURN_NOT_OK(this->data_buffer->Resize(num_values * sizeof(T), false));
-    *out = reinterpret_cast<T*>(this->data_buffer->mutable_data());
-    return Status::OK();
-  }
-
-  MemoryPool* memory_pool;
-  ArrowWriterProperties* properties;
-
-  // Buffer used for storing the data of an array converted to the physical type
-  // as expected by parquet-cpp.
-  std::shared_ptr<ResizableBuffer> data_buffer;
-
-  // We use the shared ownership of this buffer
-  std::shared_ptr<ResizableBuffer> def_levels_buffer;
-};
-
-Status GetLeafType(const ::arrow::DataType& type, ::arrow::Type::type* leaf_type) {
-  if (type.id() == ::arrow::Type::LIST || type.id() == ::arrow::Type::STRUCT) {
-    if (type.num_children() != 1) {
-      return Status::Invalid("Nested column branch had multiple children");
-    }
-    return GetLeafType(*type.child(0)->type(), leaf_type);
-  } else {
-    *leaf_type = type.id();
-    return Status::OK();
-  }
-}
-
-class ArrowColumnWriter {
- public:
-  ArrowColumnWriter(ColumnWriterContext* ctx, ColumnWriter* column_writer,
-                    const std::shared_ptr<Field>& field)
-      : ctx_(ctx), writer_(column_writer), field_(field) {}
-
-  Status Write(const Array& data);
-
-  Status Write(const ChunkedArray& data, int64_t offset, const int64_t size) {
-    int64_t absolute_position = 0;
-    int chunk_index = 0;
-    int64_t chunk_offset = 0;
-    while (chunk_index < data.num_chunks() && absolute_position < offset) {
-      const int64_t chunk_length = data.chunk(chunk_index)->length();
-      if (absolute_position + chunk_length > offset) {
-        // Relative offset into the chunk to reach the desired start offset for
-        // writing
-        chunk_offset = offset - absolute_position;
-        break;
-      } else {
-        ++chunk_index;
-        absolute_position += chunk_length;
-      }
-    }
-
-    if (absolute_position >= data.length()) {
-      return Status::Invalid("Cannot write data at offset past end of chunked array");
-    }
-
-    int64_t values_written = 0;
-    while (values_written < size) {
-      const Array& chunk = *data.chunk(chunk_index);
-      const int64_t available_values = chunk.length() - chunk_offset;
-      const int64_t chunk_write_size = std::min(size - values_written, available_values);
-
-      // The chunk offset here will be 0 except for possibly the first chunk
-      // because of the advancing logic above
-      std::shared_ptr<Array> array_to_write = chunk.Slice(chunk_offset, chunk_write_size);
-      RETURN_NOT_OK(Write(*array_to_write));
-
-      if (chunk_write_size == available_values) {
-        chunk_offset = 0;
-        ++chunk_index;
-      }
-      values_written += chunk_write_size;
-    }
-
-    return Status::OK();
-  }
-
-  Status Close() {
-    PARQUET_CATCH_NOT_OK(writer_->Close());
-    return Status::OK();
-  }
-
- private:
-  template <typename ParquetType, typename ArrowType>
-  Status TypedWriteBatch(const Array& data, int64_t num_levels, const int16_t* def_levels,
-                         const int16_t* rep_levels);
-
-  Status WriteTimestamps(const Array& data, int64_t num_levels, const int16_t* def_levels,
-                         const int16_t* rep_levels);
-
-  Status WriteTimestampsCoerce(const Array& data, int64_t num_levels,
-                               const int16_t* def_levels, const int16_t* rep_levels);
-
-  template <typename ParquetType, typename ArrowType>
-  Status WriteNonNullableBatch(const ArrowType& type, int64_t num_values,
-                               int64_t num_levels, const int16_t* def_levels,
-                               const int16_t* rep_levels,
-                               const typename ArrowType::c_type* values);
-
-  template <typename ParquetType, typename ArrowType>
-  Status WriteNullableBatch(const ArrowType& type, int64_t num_values, int64_t num_levels,
-                            const int16_t* def_levels, const int16_t* rep_levels,
-                            const uint8_t* valid_bits, int64_t valid_bits_offset,
-                            const typename ArrowType::c_type* values);
-
-  template <typename ParquetType>
-  Status WriteBatch(int64_t num_levels, const int16_t* def_levels,
-                    const int16_t* rep_levels,
-                    const typename ParquetType::c_type* values) {
-    auto typed_writer = static_cast<TypedColumnWriter<ParquetType>*>(writer_);
-    PARQUET_CATCH_NOT_OK(
-        typed_writer->WriteBatch(num_levels, def_levels, rep_levels, values));
-    return Status::OK();
-  }
-
-  template <typename ParquetType>
-  Status WriteBatchSpaced(int64_t num_levels, const int16_t* def_levels,
-                          const int16_t* rep_levels, const uint8_t* valid_bits,
-                          int64_t valid_bits_offset,
-                          const typename ParquetType::c_type* values) {
-    auto typed_writer = static_cast<TypedColumnWriter<ParquetType>*>(writer_);
-    PARQUET_CATCH_NOT_OK(typed_writer->WriteBatchSpaced(
-        num_levels, def_levels, rep_levels, valid_bits, valid_bits_offset, values));
-    return Status::OK();
-  }
-
-  ColumnWriterContext* ctx_;
-  ColumnWriter* writer_;
-  std::shared_ptr<Field> field_;
-};
-
-template <typename ParquetType, typename ArrowType>
-Status ArrowColumnWriter::TypedWriteBatch(const Array& array, int64_t num_levels,
-                                          const int16_t* def_levels,
-                                          const int16_t* rep_levels) {
-  using ArrowCType = typename ArrowType::c_type;
-
-  const auto& data = static_cast<const PrimitiveArray&>(array);
-  const ArrowCType* values = nullptr;
-  // The values buffer may be null if the array is empty (ARROW-2744)
-  if (data.values() != nullptr) {
-    values = reinterpret_cast<const ArrowCType*>(data.values()->data()) + data.offset();
-  } else {
-    DCHECK_EQ(data.length(), 0);
-  }
-
-  if (writer_->descr()->schema_node()->is_required() || (data.null_count() == 0)) {
-    // no nulls, just dump the data
-    RETURN_NOT_OK((WriteNonNullableBatch<ParquetType, ArrowType>(
-        static_cast<const ArrowType&>(*array.type()), array.length(), num_levels,
-        def_levels, rep_levels, values)));
-  } else {
-    const uint8_t* valid_bits = data.null_bitmap_data();
-    RETURN_NOT_OK((WriteNullableBatch<ParquetType, ArrowType>(
-        static_cast<const ArrowType&>(*array.type()), data.length(), num_levels,
-        def_levels, rep_levels, valid_bits, data.offset(), values)));
-  }
-  return Status::OK();
-}
-
-template <typename ParquetType, typename ArrowType>
-Status ArrowColumnWriter::WriteNonNullableBatch(
-    const ArrowType& type, int64_t num_values, int64_t num_levels,
-    const int16_t* def_levels, const int16_t* rep_levels,
-    const typename ArrowType::c_type* values) {
-  using ParquetCType = typename ParquetType::c_type;
-  ParquetCType* buffer;
-  RETURN_NOT_OK(ctx_->GetScratchData<ParquetCType>(num_values, &buffer));
-
-  std::copy(values, values + num_values, buffer);
-
-  return WriteBatch<ParquetType>(num_levels, def_levels, rep_levels, buffer);
-}
-
-template <>
-Status ArrowColumnWriter::WriteNonNullableBatch<Int32Type, ::arrow::Date64Type>(
-    const ::arrow::Date64Type& type, int64_t num_values, int64_t num_levels,
-    const int16_t* def_levels, const int16_t* rep_levels, const int64_t* values) {
-  int32_t* buffer;
-  RETURN_NOT_OK(ctx_->GetScratchData<int32_t>(num_levels, &buffer));
-
-  for (int i = 0; i < num_values; i++) {
-    buffer[i] = static_cast<int32_t>(values[i] / 86400000);
-  }
-
-  return WriteBatch<Int32Type>(num_levels, def_levels, rep_levels, buffer);
-}
-
-template <>
-Status ArrowColumnWriter::WriteNonNullableBatch<Int32Type, ::arrow::Time32Type>(
-    const ::arrow::Time32Type& type, int64_t num_values, int64_t num_levels,
-    const int16_t* def_levels, const int16_t* rep_levels, const int32_t* values) {
-  int32_t* buffer;
-  RETURN_NOT_OK(ctx_->GetScratchData<int32_t>(num_levels, &buffer));
-  if (type.unit() == TimeUnit::SECOND) {
-    for (int i = 0; i < num_values; i++) {
-      buffer[i] = values[i] * 1000;
-    }
-  } else {
-    std::copy(values, values + num_values, buffer);
-  }
-  return WriteBatch<Int32Type>(num_levels, def_levels, rep_levels, buffer);
-}
-
-#define NONNULLABLE_BATCH_FAST_PATH(ParquetType, ArrowType, CType)                 \
-  template <>                                                                      \
-  Status ArrowColumnWriter::WriteNonNullableBatch<ParquetType, ArrowType>(         \
-      const ArrowType& type, int64_t num_values, int64_t num_levels,               \
-      const int16_t* def_levels, const int16_t* rep_levels, const CType* buffer) { \
-    return WriteBatch<ParquetType>(num_levels, def_levels, rep_levels, buffer);    \
-  }
-
-NONNULLABLE_BATCH_FAST_PATH(Int32Type, ::arrow::Int32Type, int32_t)
-NONNULLABLE_BATCH_FAST_PATH(Int32Type, ::arrow::Date32Type, int32_t)
-NONNULLABLE_BATCH_FAST_PATH(Int64Type, ::arrow::Int64Type, int64_t)
-NONNULLABLE_BATCH_FAST_PATH(Int64Type, ::arrow::Time64Type, int64_t)
-NONNULLABLE_BATCH_FAST_PATH(FloatType, ::arrow::FloatType, float)
-NONNULLABLE_BATCH_FAST_PATH(DoubleType, ::arrow::DoubleType, double)
-
-template <typename ParquetType, typename ArrowType>
-Status ArrowColumnWriter::WriteNullableBatch(
-    const ArrowType& type, int64_t num_values, int64_t num_levels,
-    const int16_t* def_levels, const int16_t* rep_levels, const uint8_t* valid_bits,
-    int64_t valid_bits_offset, const typename ArrowType::c_type* values) {
-  using ParquetCType = typename ParquetType::c_type;
-
-  ParquetCType* buffer;
-  RETURN_NOT_OK(ctx_->GetScratchData<ParquetCType>(num_levels, &buffer));
-  for (int i = 0; i < num_values; i++) {
-    buffer[i] = static_cast<ParquetCType>(values[i]);
-  }
-
-  return WriteBatchSpaced<ParquetType>(num_levels, def_levels, rep_levels, valid_bits,
-                                       valid_bits_offset, buffer);
-}
-
-template <>
-Status ArrowColumnWriter::WriteNullableBatch<Int32Type, ::arrow::Date64Type>(
-    const ::arrow::Date64Type& type, int64_t num_values, int64_t num_levels,
-    const int16_t* def_levels, const int16_t* rep_levels, const uint8_t* valid_bits,
-    int64_t valid_bits_offset, const int64_t* values) {
-  int32_t* buffer;
-  RETURN_NOT_OK(ctx_->GetScratchData<int32_t>(num_values, &buffer));
-
-  for (int i = 0; i < num_values; i++) {
-    // Convert from milliseconds into days since the epoch
-    buffer[i] = static_cast<int32_t>(values[i] / 86400000);
-  }
-
-  return WriteBatchSpaced<Int32Type>(num_levels, def_levels, rep_levels, valid_bits,
-                                     valid_bits_offset, buffer);
-}
-
-template <>
-Status ArrowColumnWriter::WriteNullableBatch<Int32Type, ::arrow::Time32Type>(
-    const ::arrow::Time32Type& type, int64_t num_values, int64_t num_levels,
-    const int16_t* def_levels, const int16_t* rep_levels, const uint8_t* valid_bits,
-    int64_t valid_bits_offset, const int32_t* values) {
-  int32_t* buffer;
-  RETURN_NOT_OK(ctx_->GetScratchData<int32_t>(num_values, &buffer));
-
-  if (type.unit() == TimeUnit::SECOND) {
-    for (int i = 0; i < num_values; i++) {
-      buffer[i] = values[i] * 1000;
-    }
-  } else {
-    for (int i = 0; i < num_values; i++) {
-      buffer[i] = values[i];
-    }
-  }
-  return WriteBatchSpaced<Int32Type>(num_levels, def_levels, rep_levels, valid_bits,
-                                     valid_bits_offset, buffer);
-}
-
-#define NULLABLE_BATCH_FAST_PATH(ParquetType, ArrowType, CType)                          \
-  template <>                                                                            \
-  Status ArrowColumnWriter::WriteNullableBatch<ParquetType, ArrowType>(                  \
-      const ArrowType& type, int64_t num_values, int64_t num_levels,                     \
-      const int16_t* def_levels, const int16_t* rep_levels, const uint8_t* valid_bits,   \
-      int64_t valid_bits_offset, const CType* values) {                                  \
-    return WriteBatchSpaced<ParquetType>(num_levels, def_levels, rep_levels, valid_bits, \
-                                         valid_bits_offset, values);                     \
-  }
-
-NULLABLE_BATCH_FAST_PATH(Int32Type, ::arrow::Int32Type, int32_t)
-NULLABLE_BATCH_FAST_PATH(Int32Type, ::arrow::Date32Type, int32_t)
-NULLABLE_BATCH_FAST_PATH(Int64Type, ::arrow::Int64Type, int64_t)
-NULLABLE_BATCH_FAST_PATH(Int64Type, ::arrow::Time64Type, int64_t)
-NULLABLE_BATCH_FAST_PATH(FloatType, ::arrow::FloatType, float)
-NULLABLE_BATCH_FAST_PATH(DoubleType, ::arrow::DoubleType, double)
-NULLABLE_BATCH_FAST_PATH(Int64Type, ::arrow::TimestampType, int64_t)
-NONNULLABLE_BATCH_FAST_PATH(Int64Type, ::arrow::TimestampType, int64_t)
-
-template <>
-Status ArrowColumnWriter::WriteNullableBatch<Int96Type, ::arrow::TimestampType>(
-    const ::arrow::TimestampType& type, int64_t num_values, int64_t num_levels,
-    const int16_t* def_levels, const int16_t* rep_levels, const uint8_t* valid_bits,
-    int64_t valid_bits_offset, const int64_t* values) {
-  Int96* buffer;
-  RETURN_NOT_OK(ctx_->GetScratchData<Int96>(num_values, &buffer));
-  if (type.unit() == TimeUnit::NANO) {
-    for (int i = 0; i < num_values; i++) {
-      internal::NanosecondsToImpalaTimestamp(values[i], &buffer[i]);
-    }
-  } else {
-    return Status::NotImplemented("Only NANO timestamps are supported for Int96 writing");
-  }
-  return WriteBatchSpaced<Int96Type>(num_levels, def_levels, rep_levels, valid_bits,
-                                     valid_bits_offset, buffer);
-}
-
-template <>
-Status ArrowColumnWriter::WriteNonNullableBatch<Int96Type, ::arrow::TimestampType>(
-    const ::arrow::TimestampType& type, int64_t num_values, int64_t num_levels,
-    const int16_t* def_levels, const int16_t* rep_levels, const int64_t* values) {
-  Int96* buffer;
-  RETURN_NOT_OK(ctx_->GetScratchData<Int96>(num_values, &buffer));
-  if (type.unit() == TimeUnit::NANO) {
-    for (int i = 0; i < num_values; i++) {
-      internal::NanosecondsToImpalaTimestamp(values[i], buffer + i);
-    }
-  } else {
-    return Status::NotImplemented("Only NANO timestamps are supported for Int96 writing");
-  }
-  return WriteBatch<Int96Type>(num_levels, def_levels, rep_levels, buffer);
-}
-
-Status ArrowColumnWriter::WriteTimestamps(const Array& values, int64_t num_levels,
-                                          const int16_t* def_levels,
-                                          const int16_t* rep_levels) {
-  const auto& type = static_cast<const ::arrow::TimestampType&>(*values.type());
-
-  const bool is_nanosecond = type.unit() == TimeUnit::NANO;
-
-  // In the case where support_deprecated_int96_timestamps was specified
-  // and coerce_timestamps_enabled was specified, a nanosecond column
-  // will have a physical type of int64. In that case, we fall through
-  // to the else if below.
-  //
-  // See https://issues.apache.org/jira/browse/ARROW-2082
-  if (is_nanosecond && ctx_->properties->support_deprecated_int96_timestamps() &&
-      !ctx_->properties->coerce_timestamps_enabled()) {
-    return TypedWriteBatch<Int96Type, ::arrow::TimestampType>(values, num_levels,
-                                                              def_levels, rep_levels);
-  } else if (is_nanosecond ||
-             (ctx_->properties->coerce_timestamps_enabled() &&
-              (type.unit() != ctx_->properties->coerce_timestamps_unit()))) {
-    // Casting is required. This covers several cases
-    // * Nanoseconds -> cast to microseconds
-    // * coerce_timestamps_enabled_, cast all timestamps to requested unit
-    return WriteTimestampsCoerce(values, num_levels, def_levels, rep_levels);
-  } else {
-    // No casting of timestamps is required, take the fast path
-    return TypedWriteBatch<Int64Type, ::arrow::TimestampType>(values, num_levels,
-                                                              def_levels, rep_levels);
-  }
-}
-
-Status ArrowColumnWriter::WriteTimestampsCoerce(const Array& array, int64_t num_levels,
-                                                const int16_t* def_levels,
-                                                const int16_t* rep_levels) {
-  int64_t* buffer;
-  RETURN_NOT_OK(ctx_->GetScratchData<int64_t>(num_levels, &buffer));
-
-  const auto& data = static_cast<const ::arrow::TimestampArray&>(array);
-
-  auto values = data.raw_values();
-  const auto& type = static_cast<const ::arrow::TimestampType&>(*array.type());
-
-  TimeUnit::type target_unit = ctx_->properties->coerce_timestamps_enabled()
-                                   ? ctx_->properties->coerce_timestamps_unit()
-                                   : TimeUnit::MICRO;
-  auto target_type = ::arrow::timestamp(target_unit);
-
-  auto DivideBy = [&](const int64_t factor) {
-    for (int64_t i = 0; i < array.length(); i++) {
-      if (!data.IsNull(i) && (values[i] % factor != 0)) {
-        std::stringstream ss;
-        ss << "Casting from " << type.ToString() << " to " << target_type->ToString()
-           << " would lose data: " << values[i];
-        return Status::Invalid(ss.str());
-      }
-      buffer[i] = values[i] / factor;
-    }
-    return Status::OK();
-  };
-
-  auto MultiplyBy = [&](const int64_t factor) {
-    for (int64_t i = 0; i < array.length(); i++) {
-      buffer[i] = values[i] * factor;
-    }
-    return Status::OK();
-  };
-
-  if (type.unit() == TimeUnit::NANO) {
-    if (target_unit == TimeUnit::MICRO) {
-      RETURN_NOT_OK(DivideBy(1000));
-    } else {
-      DCHECK_EQ(TimeUnit::MILLI, target_unit);
-      RETURN_NOT_OK(DivideBy(1000000));
-    }
-  } else if (type.unit() == TimeUnit::SECOND) {
-    RETURN_NOT_OK(MultiplyBy(target_unit == TimeUnit::MICRO ? 1000000 : 1000));
-  } else if (type.unit() == TimeUnit::MILLI) {
-    DCHECK_EQ(TimeUnit::MICRO, target_unit);
-    RETURN_NOT_OK(MultiplyBy(1000));
-  } else {
-    DCHECK_EQ(TimeUnit::MILLI, target_unit);
-    RETURN_NOT_OK(DivideBy(1000));
-  }
-
-  if (writer_->descr()->schema_node()->is_required() || (data.null_count() == 0)) {
-    // no nulls, just dump the data
-    RETURN_NOT_OK((WriteNonNullableBatch<Int64Type, ::arrow::TimestampType>(
-        static_cast<const ::arrow::TimestampType&>(*target_type), array.length(),
-        num_levels, def_levels, rep_levels, buffer)));
-  } else {
-    const uint8_t* valid_bits = data.null_bitmap_data();
-    RETURN_NOT_OK((WriteNullableBatch<Int64Type, ::arrow::TimestampType>(
-        static_cast<const ::arrow::TimestampType&>(*target_type), array.length(),
-        num_levels, def_levels, rep_levels, valid_bits, data.offset(), buffer)));
-  }
-  return Status::OK();
-}
-
-// This specialization seems quite similar but it significantly differs in two points:
-// * offset is added at the most latest time to the pointer as we have sub-byte access
-// * Arrow data is stored bitwise thus we cannot use std::copy to transform from
-//   ArrowType::c_type to ParquetType::c_type
-
-template <>
-Status ArrowColumnWriter::TypedWriteBatch<BooleanType, ::arrow::BooleanType>(
-    const Array& array, int64_t num_levels, const int16_t* def_levels,
-    const int16_t* rep_levels) {
-  bool* buffer;
-  RETURN_NOT_OK(ctx_->GetScratchData<bool>(array.length(), &buffer));
-
-  const auto& data = static_cast<const BooleanArray&>(array);
-  const uint8_t* values = nullptr;
-  // The values buffer may be null if the array is empty (ARROW-2744)
-  if (data.values() != nullptr) {
-    values = reinterpret_cast<const uint8_t*>(data.values()->data());
-  } else {
-    DCHECK_EQ(data.length(), 0);
-  }
-
-  int buffer_idx = 0;
-  int64_t offset = array.offset();
-  for (int i = 0; i < data.length(); i++) {
-    if (!data.IsNull(i)) {
-      buffer[buffer_idx++] = BitUtil::GetBit(values, offset + i);
-    }
-  }
-
-  return WriteBatch<BooleanType>(num_levels, def_levels, rep_levels, buffer);
-}
-
-template <>
-Status ArrowColumnWriter::TypedWriteBatch<Int32Type, ::arrow::NullType>(
-    const Array& array, int64_t num_levels, const int16_t* def_levels,
-    const int16_t* rep_levels) {
-  return WriteBatch<Int32Type>(num_levels, def_levels, rep_levels, nullptr);
-}
-
-template <>
-Status ArrowColumnWriter::TypedWriteBatch<ByteArrayType, ::arrow::BinaryType>(
-    const Array& array, int64_t num_levels, const int16_t* def_levels,
-    const int16_t* rep_levels) {
-  ByteArray* buffer;
-  RETURN_NOT_OK(ctx_->GetScratchData<ByteArray>(num_levels, &buffer));
-
-  const auto& data = static_cast<const BinaryArray&>(array);
-
-  // In the case of an array consisting of only empty strings or all null,
-  // data.data() points already to a nullptr, thus data.data()->data() will
-  // segfault.
-  const uint8_t* values = nullptr;
-  if (data.value_data()) {
-    values = reinterpret_cast<const uint8_t*>(data.value_data()->data());
-    DCHECK(values != nullptr);
-  }
-
-  // Slice offset is accounted for in raw_value_offsets
-  const int32_t* value_offset = data.raw_value_offsets();
-
-  if (writer_->descr()->schema_node()->is_required() || (data.null_count() == 0)) {
-    // no nulls, just dump the data
-    for (int64_t i = 0; i < data.length(); i++) {
-      buffer[i] =
-          ByteArray(value_offset[i + 1] - value_offset[i], values + value_offset[i]);
-    }
-  } else {
-    int buffer_idx = 0;
-    for (int64_t i = 0; i < data.length(); i++) {
-      if (!data.IsNull(i)) {
-        buffer[buffer_idx++] =
-            ByteArray(value_offset[i + 1] - value_offset[i], values + value_offset[i]);
-      }
-    }
-  }
-
-  return WriteBatch<ByteArrayType>(num_levels, def_levels, rep_levels, buffer);
-}
-
-template <>
-Status ArrowColumnWriter::TypedWriteBatch<FLBAType, ::arrow::FixedSizeBinaryType>(
-    const Array& array, int64_t num_levels, const int16_t* def_levels,
-    const int16_t* rep_levels) {
-  const auto& data = static_cast<const FixedSizeBinaryArray&>(array);
-  const int64_t length = data.length();
-
-  FLBA* buffer;
-  RETURN_NOT_OK(ctx_->GetScratchData<FLBA>(num_levels, &buffer));
-
-  if (writer_->descr()->schema_node()->is_required() || data.null_count() == 0) {
-    // no nulls, just dump the data
-    // todo(advancedxy): use a writeBatch to avoid this step
-    for (int64_t i = 0; i < length; i++) {
-      buffer[i] = FixedLenByteArray(data.GetValue(i));
-    }
-  } else {
-    int buffer_idx = 0;
-    for (int64_t i = 0; i < length; i++) {
-      if (!data.IsNull(i)) {
-        buffer[buffer_idx++] = FixedLenByteArray(data.GetValue(i));
-      }
-    }
-  }
-
-  return WriteBatch<FLBAType>(num_levels, def_levels, rep_levels, buffer);
-}
-
-template <>
-Status ArrowColumnWriter::TypedWriteBatch<FLBAType, ::arrow::Decimal128Type>(
-    const Array& array, int64_t num_levels, const int16_t* def_levels,
-    const int16_t* rep_levels) {
-  const auto& data = static_cast<const Decimal128Array&>(array);
-  const int64_t length = data.length();
-
-  FLBA* buffer;
-  RETURN_NOT_OK(ctx_->GetScratchData<FLBA>(num_levels, &buffer));
-
-  const auto& decimal_type = static_cast<const ::arrow::Decimal128Type&>(*data.type());
-  const int32_t offset =
-      decimal_type.byte_width() - DecimalSize(decimal_type.precision());
-
-  const bool does_not_have_nulls =
-      writer_->descr()->schema_node()->is_required() || data.null_count() == 0;
-
-  const auto valid_value_count = static_cast<size_t>(length - data.null_count()) * 2;
-  std::vector<uint64_t> big_endian_values(valid_value_count);
-
-  // TODO(phillipc): Look into whether our compilers will perform loop unswitching so we
-  // don't have to keep writing two loops to handle the case where we know there are no
-  // nulls
-  if (does_not_have_nulls) {
-    // no nulls, just dump the data
-    // todo(advancedxy): use a writeBatch to avoid this step
-    for (int64_t i = 0, j = 0; i < length; ++i, j += 2) {
-      auto unsigned_64_bit = reinterpret_cast<const uint64_t*>(data.GetValue(i));
-      big_endian_values[j] = ::arrow::BitUtil::ToBigEndian(unsigned_64_bit[1]);
-      big_endian_values[j + 1] = ::arrow::BitUtil::ToBigEndian(unsigned_64_bit[0]);
-      buffer[i] = FixedLenByteArray(
-          reinterpret_cast<const uint8_t*>(&big_endian_values[j]) + offset);
-    }
-  } else {
-    for (int64_t i = 0, buffer_idx = 0, j = 0; i < length; ++i) {
-      if (!data.IsNull(i)) {
-        auto unsigned_64_bit = reinterpret_cast<const uint64_t*>(data.GetValue(i));
-        big_endian_values[j] = ::arrow::BitUtil::ToBigEndian(unsigned_64_bit[1]);
-        big_endian_values[j + 1] = ::arrow::BitUtil::ToBigEndian(unsigned_64_bit[0]);
-        buffer[buffer_idx++] = FixedLenByteArray(
-            reinterpret_cast<const uint8_t*>(&big_endian_values[j]) + offset);
-        j += 2;
-      }
-    }
-  }
-
-  return WriteBatch<FLBAType>(num_levels, def_levels, rep_levels, buffer);
-}
-
-Status ArrowColumnWriter::Write(const Array& data) {
-  ::arrow::Type::type values_type;
-  RETURN_NOT_OK(GetLeafType(*data.type(), &values_type));
-
-  std::shared_ptr<Array> _values_array;
-  int64_t values_offset;
-  int64_t num_levels;
-  int64_t num_values;
-  LevelBuilder level_builder(ctx_->memory_pool);
-
-  std::shared_ptr<Buffer> def_levels_buffer, rep_levels_buffer;
-  RETURN_NOT_OK(level_builder.GenerateLevels(
-      data, field_, &values_offset, &num_values, &num_levels, ctx_->def_levels_buffer,
-      &def_levels_buffer, &rep_levels_buffer, &_values_array));
-  const int16_t* def_levels = nullptr;
-  if (def_levels_buffer) {
-    def_levels = reinterpret_cast<const int16_t*>(def_levels_buffer->data());
-  }
-  const int16_t* rep_levels = nullptr;
-  if (rep_levels_buffer) {
-    rep_levels = reinterpret_cast<const int16_t*>(rep_levels_buffer->data());
-  }
-  std::shared_ptr<Array> values_array = _values_array->Slice(values_offset, num_values);
-
-#define WRITE_BATCH_CASE(ArrowEnum, ArrowType, ParquetType)                            \
-  case ::arrow::Type::ArrowEnum:                                                       \
-    return TypedWriteBatch<ParquetType, ::arrow::ArrowType>(*values_array, num_levels, \
-                                                            def_levels, rep_levels);
-
-  switch (values_type) {
-    case ::arrow::Type::UINT32: {
-      if (writer_->properties()->version() == ParquetVersion::PARQUET_1_0) {
-        // Parquet 1.0 reader cannot read the UINT_32 logical type. Thus we need
-        // to use the larger Int64Type to store them lossless.
-        return TypedWriteBatch<Int64Type, ::arrow::UInt32Type>(*values_array, num_levels,
-                                                               def_levels, rep_levels);
-      } else {
-        return TypedWriteBatch<Int32Type, ::arrow::UInt32Type>(*values_array, num_levels,
-                                                               def_levels, rep_levels);
-      }
-    }
-      WRITE_BATCH_CASE(NA, NullType, Int32Type)
-    case ::arrow::Type::TIMESTAMP:
-      return WriteTimestamps(*values_array, num_levels, def_levels, rep_levels);
-      WRITE_BATCH_CASE(BOOL, BooleanType, BooleanType)
-      WRITE_BATCH_CASE(INT8, Int8Type, Int32Type)
-      WRITE_BATCH_CASE(UINT8, UInt8Type, Int32Type)
-      WRITE_BATCH_CASE(INT16, Int16Type, Int32Type)
-      WRITE_BATCH_CASE(UINT16, UInt16Type, Int32Type)
-      WRITE_BATCH_CASE(INT32, Int32Type, Int32Type)
-      WRITE_BATCH_CASE(INT64, Int64Type, Int64Type)
-      WRITE_BATCH_CASE(UINT64, UInt64Type, Int64Type)
-      WRITE_BATCH_CASE(FLOAT, FloatType, FloatType)
-      WRITE_BATCH_CASE(DOUBLE, DoubleType, DoubleType)
-      WRITE_BATCH_CASE(BINARY, BinaryType, ByteArrayType)
-      WRITE_BATCH_CASE(STRING, BinaryType, ByteArrayType)
-      WRITE_BATCH_CASE(FIXED_SIZE_BINARY, FixedSizeBinaryType, FLBAType)
-      WRITE_BATCH_CASE(DECIMAL, Decimal128Type, FLBAType)
-      WRITE_BATCH_CASE(DATE32, Date32Type, Int32Type)
-      WRITE_BATCH_CASE(DATE64, Date64Type, Int32Type)
-      WRITE_BATCH_CASE(TIME32, Time32Type, Int32Type)
-      WRITE_BATCH_CASE(TIME64, Time64Type, Int64Type)
-    default:
-      break;
-  }
-  std::stringstream ss;
-  ss << "Data type not supported as list value: " << values_array->type()->ToString();
-  return Status::NotImplemented(ss.str());
-}
-
-}  // namespace
-
-// ----------------------------------------------------------------------
-// FileWriter implementation
-
-class FileWriter::Impl {
- public:
-  Impl(MemoryPool* pool, std::unique_ptr<ParquetFileWriter> writer,
-       const std::shared_ptr<ArrowWriterProperties>& arrow_properties)
-      : writer_(std::move(writer)),
-        row_group_writer_(nullptr),
-        column_write_context_(pool, arrow_properties.get()),
-        arrow_properties_(arrow_properties),
-        closed_(false) {}
-
-  Status NewRowGroup(int64_t chunk_size) {
-    if (row_group_writer_ != nullptr) {
-      PARQUET_CATCH_NOT_OK(row_group_writer_->Close());
-    }
-    PARQUET_CATCH_NOT_OK(row_group_writer_ = writer_->AppendRowGroup());
-    return Status::OK();
-  }
-
-  Status Close() {
-    if (!closed_) {
-      // Make idempotent
-      closed_ = true;
-      if (row_group_writer_ != nullptr) {
-        PARQUET_CATCH_NOT_OK(row_group_writer_->Close());
-      }
-      PARQUET_CATCH_NOT_OK(writer_->Close());
-    }
-    return Status::OK();
-  }
-
-  Status WriteColumnChunk(const Array& data) {
-    // A bit awkward here since cannot instantiate ChunkedArray from const Array&
-    ::arrow::ArrayVector chunks = {::arrow::MakeArray(data.data())};
-    auto chunked_array = std::make_shared<::arrow::ChunkedArray>(chunks);
-    return WriteColumnChunk(chunked_array, 0, data.length());
-  }
-
-  Status WriteColumnChunk(const std::shared_ptr<ChunkedArray>& data, int64_t offset,
-                          const int64_t size) {
-    // DictionaryArrays are not yet handled with a fast path. To still support
-    // writing them as a workaround, we convert them back to their non-dictionary
-    // representation.
-    if (data->type()->id() == ::arrow::Type::DICTIONARY) {
-      const ::arrow::DictionaryType& dict_type =
-          static_cast<const ::arrow::DictionaryType&>(*data->type());
-
-      // TODO(ARROW-1648): Remove this special handling once we require an Arrow
-      // version that has this fixed.
-      if (dict_type.dictionary()->type()->id() == ::arrow::Type::NA) {
-        auto null_array = std::make_shared<::arrow::NullArray>(data->length());
-        return WriteColumnChunk(*null_array);
-      }
-
-      FunctionContext ctx(this->memory_pool());
-      ::arrow::compute::Datum cast_input(data);
-      ::arrow::compute::Datum cast_output;
-      RETURN_NOT_OK(Cast(&ctx, cast_input, dict_type.dictionary()->type(), CastOptions(),
-                         &cast_output));
-      return WriteColumnChunk(cast_output.chunked_array(), offset, size);
-    }
-
-    ColumnWriter* column_writer;
-    PARQUET_CATCH_NOT_OK(column_writer = row_group_writer_->NextColumn());
-
-    // TODO(wesm): This trick to construct a schema for one Parquet root node
-    // will not work for arbitrary nested data
-    int current_column_idx = row_group_writer_->current_column();
-    std::shared_ptr<::arrow::Schema> arrow_schema;
-    RETURN_NOT_OK(FromParquetSchema(writer_->schema(), {current_column_idx - 1},
-                                    writer_->key_value_metadata(), &arrow_schema));
-
-    ArrowColumnWriter arrow_writer(&column_write_context_, column_writer,
-                                   arrow_schema->field(0));
-
-    RETURN_NOT_OK(arrow_writer.Write(*data, offset, size));
-    return arrow_writer.Close();
-  }
-
-  const WriterProperties& properties() const { return *writer_->properties(); }
-
-  ::arrow::MemoryPool* memory_pool() const { return column_write_context_.memory_pool; }
-
-  virtual ~Impl() {}
-
- private:
-  friend class FileWriter;
-
-  std::unique_ptr<ParquetFileWriter> writer_;
-  RowGroupWriter* row_group_writer_;
-  ColumnWriterContext column_write_context_;
-  std::shared_ptr<ArrowWriterProperties> arrow_properties_;
-  bool closed_;
-};
-
-Status FileWriter::NewRowGroup(int64_t chunk_size) {
-  return impl_->NewRowGroup(chunk_size);
-}
-
-Status FileWriter::WriteColumnChunk(const ::arrow::Array& data) {
-  return impl_->WriteColumnChunk(data);
-}
-
-Status FileWriter::WriteColumnChunk(const std::shared_ptr<::arrow::ChunkedArray>& data,
-                                    const int64_t offset, const int64_t size) {
-  return impl_->WriteColumnChunk(data, offset, size);
-}
-
-Status FileWriter::WriteColumnChunk(const std::shared_ptr<::arrow::ChunkedArray>& data) {
-  return WriteColumnChunk(data, 0, data->length());
-}
-
-Status FileWriter::Close() { return impl_->Close(); }
-
-MemoryPool* FileWriter::memory_pool() const { return impl_->memory_pool(); }
-
-FileWriter::~FileWriter() {}
-
-FileWriter::FileWriter(MemoryPool* pool, std::unique_ptr<ParquetFileWriter> writer,
-                       const std::shared_ptr<ArrowWriterProperties>& arrow_properties)
-    : impl_(new FileWriter::Impl(pool, std::move(writer), arrow_properties)) {}
-
-Status FileWriter::Open(const ::arrow::Schema& schema, ::arrow::MemoryPool* pool,
-                        const std::shared_ptr<OutputStream>& sink,
-                        const std::shared_ptr<WriterProperties>& properties,
-                        std::unique_ptr<FileWriter>* writer) {
-  return Open(schema, pool, sink, properties, default_arrow_writer_properties(), writer);
-}
-
-Status FileWriter::Open(const ::arrow::Schema& schema, ::arrow::MemoryPool* pool,
-                        const std::shared_ptr<OutputStream>& sink,
-                        const std::shared_ptr<WriterProperties>& properties,
-                        const std::shared_ptr<ArrowWriterProperties>& arrow_properties,
-                        std::unique_ptr<FileWriter>* writer) {
-  std::shared_ptr<SchemaDescriptor> parquet_schema;
-  RETURN_NOT_OK(
-      ToParquetSchema(&schema, *properties, *arrow_properties, &parquet_schema));
-
-  auto schema_node = std::static_pointer_cast<GroupNode>(parquet_schema->schema_root());
-
-  std::unique_ptr<ParquetFileWriter> base_writer =
-      ParquetFileWriter::Open(sink, schema_node, properties, schema.metadata());
-
-  writer->reset(new FileWriter(pool, std::move(base_writer), arrow_properties));
-  return Status::OK();
-}
-
-Status FileWriter::Open(const ::arrow::Schema& schema, ::arrow::MemoryPool* pool,
-                        const std::shared_ptr<::arrow::io::OutputStream>& sink,
-                        const std::shared_ptr<WriterProperties>& properties,
-                        std::unique_ptr<FileWriter>* writer) {
-  auto wrapper = std::make_shared<ArrowOutputStream>(sink);
-  return Open(schema, pool, wrapper, properties, writer);
-}
-
-Status FileWriter::Open(const ::arrow::Schema& schema, ::arrow::MemoryPool* pool,
-                        const std::shared_ptr<::arrow::io::OutputStream>& sink,
-                        const std::shared_ptr<WriterProperties>& properties,
-                        const std::shared_ptr<ArrowWriterProperties>& arrow_properties,
-                        std::unique_ptr<FileWriter>* writer) {
-  auto wrapper = std::make_shared<ArrowOutputStream>(sink);
-  return Open(schema, pool, wrapper, properties, arrow_properties, writer);
-}
-
-Status WriteFileMetaData(const FileMetaData& file_metadata, OutputStream* sink) {
-  PARQUET_CATCH_NOT_OK(::parquet::WriteFileMetaData(file_metadata, sink));
-  return Status::OK();
-}
-
-Status WriteFileMetaData(const FileMetaData& file_metadata,
-                         const std::shared_ptr<::arrow::io::OutputStream>& sink) {
-  ArrowOutputStream wrapper(sink);
-  return ::parquet::arrow::WriteFileMetaData(file_metadata, &wrapper);
-}
-
-namespace {}  // namespace
-
-Status FileWriter::WriteTable(const Table& table, int64_t chunk_size) {
-  if (chunk_size <= 0) {
-    return Status::Invalid("chunk size per row_group must be greater than 0");
-  } else if (chunk_size > impl_->properties().max_row_group_length()) {
-    chunk_size = impl_->properties().max_row_group_length();
-  }
-
-  for (int chunk = 0; chunk * chunk_size < table.num_rows(); chunk++) {
-    int64_t offset = chunk * chunk_size;
-    int64_t size = std::min(chunk_size, table.num_rows() - offset);
-
-    RETURN_NOT_OK_ELSE(NewRowGroup(size), PARQUET_IGNORE_NOT_OK(Close()));
-    for (int i = 0; i < table.num_columns(); i++) {
-      auto chunked_data = table.column(i)->data();
-      RETURN_NOT_OK_ELSE(WriteColumnChunk(chunked_data, offset, size),
-                         PARQUET_IGNORE_NOT_OK(Close()));
-    }
-  }
-  return Status::OK();
-}
-
-Status WriteTable(const ::arrow::Table& table, ::arrow::MemoryPool* pool,
-                  const std::shared_ptr<OutputStream>& sink, int64_t chunk_size,
-                  const std::shared_ptr<WriterProperties>& properties,
-                  const std::shared_ptr<ArrowWriterProperties>& arrow_properties) {
-  std::unique_ptr<FileWriter> writer;
-  RETURN_NOT_OK(FileWriter::Open(*table.schema(), pool, sink, properties,
-                                 arrow_properties, &writer));
-  RETURN_NOT_OK(writer->WriteTable(table, chunk_size));
-  return writer->Close();
-}
-
-Status WriteTable(const ::arrow::Table& table, ::arrow::MemoryPool* pool,
-                  const std::shared_ptr<::arrow::io::OutputStream>& sink,
-                  int64_t chunk_size, const std::shared_ptr<WriterProperties>& properties,
-                  const std::shared_ptr<ArrowWriterProperties>& arrow_properties) {
-  auto wrapper = std::make_shared<ArrowOutputStream>(sink);
-  return WriteTable(table, pool, wrapper, chunk_size, properties, arrow_properties);
-}
-
-}  // namespace arrow
-}  // namespace parquet
diff --git a/src/parquet/arrow/writer.h b/src/parquet/arrow/writer.h
deleted file mode 100644
index ad6f1d5..0000000
--- a/src/parquet/arrow/writer.h
+++ /dev/null
@@ -1,210 +0,0 @@
-// 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.
-
-#ifndef PARQUET_ARROW_WRITER_H
-#define PARQUET_ARROW_WRITER_H
-
-#include <memory>
-
-#include "parquet/api/schema.h"
-#include "parquet/api/writer.h"
-
-#include "arrow/io/interfaces.h"
-#include "arrow/type.h"
-
-namespace arrow {
-
-class Array;
-class MemoryPool;
-class PrimitiveArray;
-class Schema;
-class Status;
-class StringArray;
-class Table;
-}  // namespace arrow
-
-namespace parquet {
-namespace arrow {
-
-class PARQUET_EXPORT ArrowWriterProperties {
- public:
-  class Builder {
-   public:
-    Builder() : write_nanos_as_int96_(false), coerce_timestamps_enabled_(false) {}
-    virtual ~Builder() {}
-
-    Builder* disable_deprecated_int96_timestamps() {
-      write_nanos_as_int96_ = false;
-      return this;
-    }
-
-    Builder* enable_deprecated_int96_timestamps() {
-      write_nanos_as_int96_ = true;
-      return this;
-    }
-
-    Builder* coerce_timestamps(::arrow::TimeUnit::type unit) {
-      coerce_timestamps_enabled_ = true;
-      coerce_timestamps_unit_ = unit;
-      return this;
-    }
-
-    std::shared_ptr<ArrowWriterProperties> build() {
-      return std::shared_ptr<ArrowWriterProperties>(new ArrowWriterProperties(
-          write_nanos_as_int96_, coerce_timestamps_enabled_, coerce_timestamps_unit_));
-    }
-
-   private:
-    bool write_nanos_as_int96_;
-
-    bool coerce_timestamps_enabled_;
-    ::arrow::TimeUnit::type coerce_timestamps_unit_;
-  };
-
-  bool support_deprecated_int96_timestamps() const { return write_nanos_as_int96_; }
-
-  bool coerce_timestamps_enabled() const { return coerce_timestamps_enabled_; }
-  ::arrow::TimeUnit::type coerce_timestamps_unit() const {
-    return coerce_timestamps_unit_;
-  }
-
- private:
-  explicit ArrowWriterProperties(bool write_nanos_as_int96,
-                                 bool coerce_timestamps_enabled,
-                                 ::arrow::TimeUnit::type coerce_timestamps_unit)
-      : write_nanos_as_int96_(write_nanos_as_int96),
-        coerce_timestamps_enabled_(coerce_timestamps_enabled),
-        coerce_timestamps_unit_(coerce_timestamps_unit) {}
-
-  const bool write_nanos_as_int96_;
-  const bool coerce_timestamps_enabled_;
-  const ::arrow::TimeUnit::type coerce_timestamps_unit_;
-};
-
-std::shared_ptr<ArrowWriterProperties> PARQUET_EXPORT default_arrow_writer_properties();
-
-/**
- * Iterative API:
- *  Start a new RowGroup/Chunk with NewRowGroup
- *  Write column-by-column the whole column chunk
- */
-class PARQUET_EXPORT FileWriter {
- public:
-  FileWriter(::arrow::MemoryPool* pool, std::unique_ptr<ParquetFileWriter> writer,
-             const std::shared_ptr<ArrowWriterProperties>& arrow_properties =
-                 default_arrow_writer_properties());
-
-  static ::arrow::Status Open(const ::arrow::Schema& schema, ::arrow::MemoryPool* pool,
-                              const std::shared_ptr<OutputStream>& sink,
-                              const std::shared_ptr<WriterProperties>& properties,
-                              std::unique_ptr<FileWriter>* writer);
-
-  static ::arrow::Status Open(
-      const ::arrow::Schema& schema, ::arrow::MemoryPool* pool,
-      const std::shared_ptr<OutputStream>& sink,
-      const std::shared_ptr<WriterProperties>& properties,
-      const std::shared_ptr<ArrowWriterProperties>& arrow_properties,
-      std::unique_ptr<FileWriter>* writer);
-
-  static ::arrow::Status Open(const ::arrow::Schema& schema, ::arrow::MemoryPool* pool,
-                              const std::shared_ptr<::arrow::io::OutputStream>& sink,
-                              const std::shared_ptr<WriterProperties>& properties,
-                              std::unique_ptr<FileWriter>* writer);
-
-  static ::arrow::Status Open(
-      const ::arrow::Schema& schema, ::arrow::MemoryPool* pool,
-      const std::shared_ptr<::arrow::io::OutputStream>& sink,
-      const std::shared_ptr<WriterProperties>& properties,
-      const std::shared_ptr<ArrowWriterProperties>& arrow_properties,
-      std::unique_ptr<FileWriter>* writer);
-
-  /// \brief Write a Table to Parquet.
-  ::arrow::Status WriteTable(const ::arrow::Table& table, int64_t chunk_size);
-
-  ::arrow::Status NewRowGroup(int64_t chunk_size);
-  ::arrow::Status WriteColumnChunk(const ::arrow::Array& data);
-
-  /// \brief Write ColumnChunk in row group using slice of a ChunkedArray
-  ::arrow::Status WriteColumnChunk(const std::shared_ptr<::arrow::ChunkedArray>& data,
-                                   const int64_t offset, const int64_t size);
-  ::arrow::Status WriteColumnChunk(const std::shared_ptr<::arrow::ChunkedArray>& data);
-  ::arrow::Status Close();
-
-  virtual ~FileWriter();
-
-  ::arrow::MemoryPool* memory_pool() const;
-
- private:
-  class PARQUET_NO_EXPORT Impl;
-  std::unique_ptr<Impl> impl_;
-};
-
-/// \brief Write Parquet file metadata only to indicated OutputStream
-PARQUET_EXPORT
-::arrow::Status WriteFileMetaData(const FileMetaData& file_metadata, OutputStream* sink);
-
-/// \brief Write Parquet file metadata only to indicated Arrow OutputStream
-PARQUET_EXPORT
-::arrow::Status WriteFileMetaData(const FileMetaData& file_metadata,
-                                  const std::shared_ptr<::arrow::io::OutputStream>& sink);
-
-/**
- * Write a Table to Parquet.
- *
- * The table shall only consist of columns of primitive type or of primitive lists.
- */
-::arrow::Status PARQUET_EXPORT WriteTable(
-    const ::arrow::Table& table, ::arrow::MemoryPool* pool,
-    const std::shared_ptr<OutputStream>& sink, int64_t chunk_size,
-    const std::shared_ptr<WriterProperties>& properties = default_writer_properties(),
-    const std::shared_ptr<ArrowWriterProperties>& arrow_properties =
-        default_arrow_writer_properties());
-
-::arrow::Status PARQUET_EXPORT WriteTable(
-    const ::arrow::Table& table, ::arrow::MemoryPool* pool,
-    const std::shared_ptr<::arrow::io::OutputStream>& sink, int64_t chunk_size,
-    const std::shared_ptr<WriterProperties>& properties = default_writer_properties(),
-    const std::shared_ptr<ArrowWriterProperties>& arrow_properties =
-        default_arrow_writer_properties());
-
-namespace internal {
-
-/**
- * Timestamp conversion constants
- */
-constexpr int64_t kJulianEpochOffsetDays = INT64_C(2440588);
-constexpr int64_t kNanosecondsPerDay = INT64_C(86400000000000);
-
-/**
- * Converts nanosecond timestamps to Impala (Int96) format
- */
-inline void NanosecondsToImpalaTimestamp(const int64_t nanoseconds,
-                                         Int96* impala_timestamp) {
-  int64_t julian_days = (nanoseconds / kNanosecondsPerDay) + kJulianEpochOffsetDays;
-  (*impala_timestamp).value[2] = (uint32_t)julian_days;
-
-  int64_t last_day_nanos = nanoseconds % kNanosecondsPerDay;
-  int64_t* impala_last_day_nanos = reinterpret_cast<int64_t*>(impala_timestamp);
-  *impala_last_day_nanos = last_day_nanos;
-}
-
-}  // namespace internal
-
-}  // namespace arrow
-}  // namespace parquet
-
-#endif  // PARQUET_ARROW_WRITER_H
diff --git a/src/parquet/bloom_filter-test.cc b/src/parquet/bloom_filter-test.cc
deleted file mode 100644
index 96d2e06..0000000
--- a/src/parquet/bloom_filter-test.cc
+++ /dev/null
@@ -1,244 +0,0 @@
-// 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.
-
-#include <gtest/gtest.h>
-
-#include <algorithm>
-#include <random>
-#include <string>
-
-#include "arrow/io/file.h"
-#include "parquet/bloom_filter.h"
-#include "parquet/murmur3.h"
-#include "parquet/util/memory.h"
-#include "parquet/util/test-common.h"
-
-namespace parquet {
-namespace test {
-TEST(Murmur3Test, TestBloomFilter) {
-  uint64_t result;
-  const uint8_t bitset[8] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7};
-  ByteArray byteArray(8, bitset);
-  MurmurHash3 murmur3;
-  result = murmur3.Hash(&byteArray);
-  EXPECT_EQ(result, UINT64_C(913737700387071329));
-}
-
-TEST(ConstructorTest, TestBloomFilter) {
-  BlockSplitBloomFilter bloom_filter;
-  EXPECT_NO_THROW(bloom_filter.Init(1000));
-
-  // It throws because the length cannot be zero
-  std::unique_ptr<uint8_t[]> bitset1(new uint8_t[1024]());
-  EXPECT_THROW(bloom_filter.Init(bitset1.get(), 0), ParquetException);
-
-  // It throws because the number of bytes of Bloom filter bitset must be a power of 2.
-  std::unique_ptr<uint8_t[]> bitset2(new uint8_t[1024]());
-  EXPECT_THROW(bloom_filter.Init(bitset2.get(), 1023), ParquetException);
-}
-
-// The BasicTest is used to test basic operations including InsertHash, FindHash and
-// serializing and de-serializing.
-TEST(BasicTest, TestBloomFilter) {
-  BlockSplitBloomFilter bloom_filter;
-  bloom_filter.Init(1024);
-
-  for (int i = 0; i < 10; i++) {
-    bloom_filter.InsertHash(bloom_filter.Hash(i));
-  }
-
-  for (int i = 0; i < 10; i++) {
-    EXPECT_TRUE(bloom_filter.FindHash(bloom_filter.Hash(i)));
-  }
-
-  // Serialize Bloom filter to memory output stream
-  InMemoryOutputStream sink;
-  bloom_filter.WriteTo(&sink);
-
-  // Deserialize Bloom filter from memory
-  InMemoryInputStream source(sink.GetBuffer());
-
-  BlockSplitBloomFilter de_bloom = BlockSplitBloomFilter::Deserialize(&source);
-
-  for (int i = 0; i < 10; i++) {
-    EXPECT_TRUE(de_bloom.FindHash(de_bloom.Hash(i)));
-  }
-}
-
-// Helper function to generate random string.
-std::string GetRandomString(uint32_t length) {
-  // Character set used to generate random string
-  const std::string charset =
-      "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
-
-  // The uuid_seed was generated by "uuidgen -r"
-  const std::string uuid_seed = "8de406aa-fb59-4195-a81c-5152af26433f";
-  std::seed_seq seed(uuid_seed.begin(), uuid_seed.end());
-  std::mt19937 generator(seed);
-  std::uniform_int_distribution<uint32_t> dist(0, static_cast<int>(charset.size() - 1));
-  std::string ret = "";
-
-  for (uint32_t i = 0; i < length; i++) {
-    ret += charset[dist(generator)];
-  }
-
-  return ret;
-}
-
-TEST(FPPTest, TestBloomFilter) {
-  // It counts the number of times FindHash returns true.
-  int exist = 0;
-
-  // Total count of elements that will be used
-#ifdef PARQUET_VALGRIND
-  const int total_count = 5000;
-#else
-  const int total_count = 100000;
-#endif
-
-  // Bloom filter fpp parameter
-  const double fpp = 0.01;
-
-  std::vector<std::string> members;
-  BlockSplitBloomFilter bloom_filter;
-  bloom_filter.Init(BlockSplitBloomFilter::OptimalNumOfBits(total_count, fpp));
-
-  // Insert elements into the Bloom filter
-  for (int i = 0; i < total_count; i++) {
-    // Insert random string which length is 8
-    std::string tmp = GetRandomString(8);
-    const ByteArray byte_array(8, reinterpret_cast<const uint8_t*>(tmp.c_str()));
-    members.push_back(tmp);
-    bloom_filter.InsertHash(bloom_filter.Hash(&byte_array));
-  }
-
-  for (int i = 0; i < total_count; i++) {
-    const ByteArray byte_array1(8, reinterpret_cast<const uint8_t*>(members[i].c_str()));
-    ASSERT_TRUE(bloom_filter.FindHash(bloom_filter.Hash(&byte_array1)));
-    std::string tmp = GetRandomString(7);
-    const ByteArray byte_array2(7, reinterpret_cast<const uint8_t*>(tmp.c_str()));
-
-    if (bloom_filter.FindHash(bloom_filter.Hash(&byte_array2))) {
-      exist++;
-    }
-  }
-
-  // The exist should be probably less than 1000 according default FPP 0.01.
-  EXPECT_TRUE(exist < total_count * fpp);
-}
-
-// The CompatibilityTest is used to test cross compatibility with parquet-mr, it reads
-// the Bloom filter binary generated by the Bloom filter class in the parquet-mr project
-// and tests whether the values inserted before could be filtered or not.
-
-// The Bloom filter binary is generated by three steps in from Parquet-mr.
-// Step 1: Construct a Bloom filter with 1024 bytes bitset.
-// Step 2: Insert "hello", "parquet", "bloom", "filter" to Bloom filter.
-// Step 3: Call writeTo API to write to File.
-TEST(CompatibilityTest, TestBloomFilter) {
-  const std::string test_string[4] = {"hello", "parquet", "bloom", "filter"};
-  const std::string bloom_filter_test_binary =
-      std::string(test::get_data_dir()) + "/bloom_filter.bin";
-  std::shared_ptr<::arrow::io::ReadableFile> handle;
-
-  int64_t size;
-  PARQUET_THROW_NOT_OK(
-      ::arrow::io::ReadableFile::Open(bloom_filter_test_binary, &handle));
-  PARQUET_THROW_NOT_OK(handle->GetSize(&size));
-
-  // 1024 bytes (bitset) + 4 bytes (hash) + 4 bytes (algorithm) + 4 bytes (length)
-  EXPECT_EQ(size, 1036);
-
-  std::unique_ptr<uint8_t[]> bitset(new uint8_t[size]());
-  std::shared_ptr<Buffer> buffer(new Buffer(bitset.get(), size));
-  PARQUET_THROW_NOT_OK(handle->Read(size, &buffer));
-
-  InMemoryInputStream source(buffer);
-  BlockSplitBloomFilter bloom_filter1 = BlockSplitBloomFilter::Deserialize(&source);
-
-  for (int i = 0; i < 4; i++) {
-    const ByteArray tmp(static_cast<uint32_t>(test_string[i].length()),
-                        reinterpret_cast<const uint8_t*>(test_string[i].c_str()));
-    EXPECT_TRUE(bloom_filter1.FindHash(bloom_filter1.Hash(&tmp)));
-  }
-
-  // The following is used to check whether the new created Bloom filter in parquet-cpp is
-  // byte-for-byte identical to file at bloom_data_path which is created from parquet-mr
-  // with same inserted hashes.
-  BlockSplitBloomFilter bloom_filter2;
-  bloom_filter2.Init(bloom_filter1.GetBitsetSize());
-  for (int i = 0; i < 4; i++) {
-    const ByteArray byte_array(static_cast<uint32_t>(test_string[i].length()),
-                               reinterpret_cast<const uint8_t*>(test_string[i].c_str()));
-    bloom_filter2.InsertHash(bloom_filter2.Hash(&byte_array));
-  }
-
-  // Serialize Bloom filter to memory output stream
-  InMemoryOutputStream sink;
-  bloom_filter2.WriteTo(&sink);
-  std::shared_ptr<Buffer> buffer1 = sink.GetBuffer();
-
-  PARQUET_THROW_NOT_OK(handle->Seek(0));
-  PARQUET_THROW_NOT_OK(handle->GetSize(&size));
-  std::shared_ptr<Buffer> buffer2;
-  PARQUET_THROW_NOT_OK(handle->Read(size, &buffer2));
-
-  EXPECT_TRUE((*buffer1).Equals(*buffer2));
-}
-
-// OptmialValueTest is used to test whether OptimalNumOfBits returns expected
-// numbers according to formula:
-//     num_of_bits = -8.0 * ndv / log(1 - pow(fpp, 1.0 / 8.0))
-// where ndv is the number of distinct values and fpp is the false positive probability.
-// Also it is used to test whether OptimalNumOfBits returns value between
-// [MINIMUM_BLOOM_FILTER_SIZE, MAXIMUM_BLOOM_FILTER_SIZE].
-TEST(OptimalValueTest, TestBloomFilter) {
-  EXPECT_EQ(BlockSplitBloomFilter::OptimalNumOfBits(256, 0.01), UINT32_C(4096));
-  EXPECT_EQ(BlockSplitBloomFilter::OptimalNumOfBits(512, 0.01), UINT32_C(8192));
-  EXPECT_EQ(BlockSplitBloomFilter::OptimalNumOfBits(1024, 0.01), UINT32_C(16384));
-  EXPECT_EQ(BlockSplitBloomFilter::OptimalNumOfBits(2048, 0.01), UINT32_C(32768));
-
-  EXPECT_EQ(BlockSplitBloomFilter::OptimalNumOfBits(200, 0.01), UINT32_C(2048));
-  EXPECT_EQ(BlockSplitBloomFilter::OptimalNumOfBits(300, 0.01), UINT32_C(4096));
-  EXPECT_EQ(BlockSplitBloomFilter::OptimalNumOfBits(700, 0.01), UINT32_C(8192));
-  EXPECT_EQ(BlockSplitBloomFilter::OptimalNumOfBits(1500, 0.01), UINT32_C(16384));
-
-  EXPECT_EQ(BlockSplitBloomFilter::OptimalNumOfBits(200, 0.025), UINT32_C(2048));
-  EXPECT_EQ(BlockSplitBloomFilter::OptimalNumOfBits(300, 0.025), UINT32_C(4096));
-  EXPECT_EQ(BlockSplitBloomFilter::OptimalNumOfBits(700, 0.025), UINT32_C(8192));
-  EXPECT_EQ(BlockSplitBloomFilter::OptimalNumOfBits(1500, 0.025), UINT32_C(16384));
-
-  EXPECT_EQ(BlockSplitBloomFilter::OptimalNumOfBits(200, 0.05), UINT32_C(2048));
-  EXPECT_EQ(BlockSplitBloomFilter::OptimalNumOfBits(300, 0.05), UINT32_C(4096));
-  EXPECT_EQ(BlockSplitBloomFilter::OptimalNumOfBits(700, 0.05), UINT32_C(8192));
-  EXPECT_EQ(BlockSplitBloomFilter::OptimalNumOfBits(1500, 0.05), UINT32_C(16384));
-
-  // Boundary check
-  EXPECT_EQ(BlockSplitBloomFilter::OptimalNumOfBits(4, 0.01), UINT32_C(256));
-  EXPECT_EQ(BlockSplitBloomFilter::OptimalNumOfBits(4, 0.25), UINT32_C(256));
-
-  EXPECT_EQ(
-      BlockSplitBloomFilter::OptimalNumOfBits(std::numeric_limits<uint32_t>::max(), 0.01),
-      UINT32_C(1073741824));
-  EXPECT_EQ(
-      BlockSplitBloomFilter::OptimalNumOfBits(std::numeric_limits<uint32_t>::max(), 0.25),
-      UINT32_C(1073741824));
-}
-
-}  // namespace test
-
-}  // namespace parquet
diff --git a/src/parquet/bloom_filter.cc b/src/parquet/bloom_filter.cc
deleted file mode 100644
index faa344c..0000000
--- a/src/parquet/bloom_filter.cc
+++ /dev/null
@@ -1,166 +0,0 @@
-// 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.
-
-#include <algorithm>
-#include <cmath>
-#include <cstdint>
-
-#include "arrow/status.h"
-#include "arrow/util/bit-util.h"
-#include "parquet/bloom_filter.h"
-#include "parquet/exception.h"
-#include "parquet/murmur3.h"
-#include "parquet/types.h"
-#include "parquet/util/logging.h"
-
-namespace parquet {
-constexpr uint32_t BlockSplitBloomFilter::SALT[kBitsSetPerBlock];
-
-BlockSplitBloomFilter::BlockSplitBloomFilter()
-    : pool_(::arrow::default_memory_pool()),
-      hash_strategy_(HashStrategy::MURMUR3_X64_128),
-      algorithm_(Algorithm::BLOCK) {}
-
-void BlockSplitBloomFilter::Init(uint32_t num_bytes) {
-  if (num_bytes < kMinimumBloomFilterBytes) {
-    num_bytes = kMinimumBloomFilterBytes;
-  }
-
-  // Get next power of 2 if it is not power of 2.
-  if ((num_bytes & (num_bytes - 1)) != 0) {
-    num_bytes = static_cast<uint32_t>(::arrow::BitUtil::NextPower2(num_bytes));
-  }
-
-  if (num_bytes > kMaximumBloomFilterBytes) {
-    num_bytes = kMaximumBloomFilterBytes;
-  }
-
-  num_bytes_ = num_bytes;
-  PARQUET_THROW_NOT_OK(::arrow::AllocateBuffer(pool_, num_bytes_, &data_));
-  memset(data_->mutable_data(), 0, num_bytes_);
-
-  this->hasher_.reset(new MurmurHash3());
-}
-
-void BlockSplitBloomFilter::Init(const uint8_t* bitset, uint32_t num_bytes) {
-  DCHECK(bitset != nullptr);
-
-  if (num_bytes < kMinimumBloomFilterBytes || num_bytes > kMaximumBloomFilterBytes ||
-      (num_bytes & (num_bytes - 1)) != 0) {
-    throw ParquetException("Given length of bitset is illegal");
-  }
-
-  num_bytes_ = num_bytes;
-  PARQUET_THROW_NOT_OK(::arrow::AllocateBuffer(pool_, num_bytes_, &data_));
-  memcpy(data_->mutable_data(), bitset, num_bytes_);
-
-  this->hasher_.reset(new MurmurHash3());
-}
-
-BlockSplitBloomFilter BlockSplitBloomFilter::Deserialize(InputStream* input) {
-  int64_t bytes_available;
-
-  const uint8_t* read_buffer = NULL;
-  read_buffer = input->Read(sizeof(uint32_t), &bytes_available);
-  if (static_cast<uint32_t>(bytes_available) != sizeof(uint32_t) || !read_buffer) {
-    throw ParquetException("Failed to deserialize from input stream");
-  }
-  uint32_t len;
-  memcpy(&len, read_buffer, sizeof(uint32_t));
-
-  read_buffer = input->Read(sizeof(uint32_t), &bytes_available);
-  if (static_cast<uint32_t>(bytes_available) != sizeof(uint32_t) || !read_buffer) {
-    throw ParquetException("Failed to deserialize from input stream");
-  }
-  uint32_t hash;
-  memcpy(&hash, read_buffer, sizeof(uint32_t));
-  if (static_cast<HashStrategy>(hash) != HashStrategy::MURMUR3_X64_128) {
-    throw ParquetException("Unsupported hash strategy");
-  }
-
-  read_buffer = input->Read(sizeof(uint32_t), &bytes_available);
-  if (static_cast<uint32_t>(bytes_available) != sizeof(uint32_t) || !read_buffer) {
-    throw ParquetException("Failed to deserialize from input stream");
-  }
-  uint32_t algorithm;
-  memcpy(&algorithm, read_buffer, sizeof(uint32_t));
-  if (static_cast<Algorithm>(algorithm) != BloomFilter::Algorithm::BLOCK) {
-    throw ParquetException("Unsupported Bloom filter algorithm");
-  }
-
-  BlockSplitBloomFilter bloom_filter;
-  bloom_filter.Init(input->Read(len, &bytes_available), len);
-  return bloom_filter;
-}
-
-void BlockSplitBloomFilter::WriteTo(OutputStream* sink) const {
-  DCHECK(sink != nullptr);
-
-  sink->Write(reinterpret_cast<const uint8_t*>(&num_bytes_), sizeof(num_bytes_));
-  sink->Write(reinterpret_cast<const uint8_t*>(&hash_strategy_), sizeof(hash_strategy_));
-  sink->Write(reinterpret_cast<const uint8_t*>(&algorithm_), sizeof(algorithm_));
-  sink->Write(data_->mutable_data(), num_bytes_);
-}
-
-void BlockSplitBloomFilter::SetMask(uint32_t key, BlockMask& block_mask) const {
-  for (int i = 0; i < kBitsSetPerBlock; ++i) {
-    block_mask.item[i] = key * SALT[i];
-  }
-
-  for (int i = 0; i < kBitsSetPerBlock; ++i) {
-    block_mask.item[i] = block_mask.item[i] >> 27;
-  }
-
-  for (int i = 0; i < kBitsSetPerBlock; ++i) {
-    block_mask.item[i] = UINT32_C(0x1) << block_mask.item[i];
-  }
-}
-
-bool BlockSplitBloomFilter::FindHash(uint64_t hash) const {
-  const uint32_t bucket_index =
-      static_cast<uint32_t>((hash >> 32) & (num_bytes_ / kBytesPerFilterBlock - 1));
-  uint32_t key = static_cast<uint32_t>(hash);
-  uint32_t* bitset32 = reinterpret_cast<uint32_t*>(data_->mutable_data());
-
-  // Calculate mask for bucket.
-  BlockMask block_mask;
-  SetMask(key, block_mask);
-
-  for (int i = 0; i < kBitsSetPerBlock; ++i) {
-    if (0 == (bitset32[kBitsSetPerBlock * bucket_index + i] & block_mask.item[i])) {
-      return false;
-    }
-  }
-  return true;
-}
-
-void BlockSplitBloomFilter::InsertHash(uint64_t hash) {
-  const uint32_t bucket_index =
-      static_cast<uint32_t>(hash >> 32) & (num_bytes_ / kBytesPerFilterBlock - 1);
-  uint32_t key = static_cast<uint32_t>(hash);
-  uint32_t* bitset32 = reinterpret_cast<uint32_t*>(data_->mutable_data());
-
-  // Calculate mask for bucket.
-  BlockMask block_mask;
-  SetMask(key, block_mask);
-
-  for (int i = 0; i < kBitsSetPerBlock; i++) {
-    bitset32[bucket_index * kBitsSetPerBlock + i] |= block_mask.item[i];
-  }
-}
-
-}  // namespace parquet
diff --git a/src/parquet/bloom_filter.h b/src/parquet/bloom_filter.h
deleted file mode 100644
index e39370a..0000000
--- a/src/parquet/bloom_filter.h
+++ /dev/null
@@ -1,244 +0,0 @@
-// 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.
-
-#ifndef PARQUET_BLOOM_FILTER_H
-#define PARQUET_BLOOM_FILTER_H
-
-#include <cstdint>
-
-#include "parquet/exception.h"
-#include "parquet/hasher.h"
-#include "parquet/types.h"
-#include "parquet/util/logging.h"
-#include "parquet/util/memory.h"
-
-namespace parquet {
-class OutputStream;
-
-// A Bloom filter is a compact structure to indicate whether an item is not in a set or
-// probably in a set. The Bloom filter usually consists of a bit set that represents a
-// set of elements, a hash strategy and a Bloom filter algorithm.
-class BloomFilter {
- public:
-  // Maximum Bloom filter size, it sets to HDFS default block size 128MB
-  // This value will be reconsidered when implementing Bloom filter producer.
-  static constexpr uint32_t kMaximumBloomFilterBytes = 128 * 1024 * 1024;
-
-  /// Determine whether an element exist in set or not.
-  ///
-  /// @param hash the element to contain.
-  /// @return false if value is definitely not in set, and true means PROBABLY
-  /// in set.
-  virtual bool FindHash(uint64_t hash) const = 0;
-
-  /// Insert element to set represented by Bloom filter bitset.
-  /// @param hash the hash of value to insert into Bloom filter.
-  virtual void InsertHash(uint64_t hash) = 0;
-
-  /// Write this Bloom filter to an output stream. A Bloom filter structure should
-  /// include bitset length, hash strategy, algorithm, and bitset.
-  ///
-  /// @param sink the output stream to write
-  virtual void WriteTo(OutputStream* sink) const = 0;
-
-  /// Get the number of bytes of bitset
-  virtual uint32_t GetBitsetSize() const = 0;
-
-  /// Compute hash for 32 bits value by using its plain encoding result.
-  ///
-  /// @param value the value to hash.
-  /// @return hash result.
-  virtual uint64_t Hash(int32_t value) const = 0;
-
-  /// Compute hash for 64 bits value by using its plain encoding result.
-  ///
-  /// @param value the value to hash.
-  /// @return hash result.
-  virtual uint64_t Hash(int64_t value) const = 0;
-
-  /// Compute hash for float value by using its plain encoding result.
-  ///
-  /// @param value the value to hash.
-  /// @return hash result.
-  virtual uint64_t Hash(float value) const = 0;
-
-  /// Compute hash for double value by using its plain encoding result.
-  ///
-  /// @param value the value to hash.
-  /// @return hash result.
-  virtual uint64_t Hash(double value) const = 0;
-
-  /// Compute hash for Int96 value by using its plain encoding result.
-  ///
-  /// @param value the value to hash.
-  /// @return hash result.
-  virtual uint64_t Hash(const Int96* value) const = 0;
-
-  /// Compute hash for ByteArray value by using its plain encoding result.
-  ///
-  /// @param value the value to hash.
-  /// @return hash result.
-  virtual uint64_t Hash(const ByteArray* value) const = 0;
-
-  /// Compute hash for fixed byte array value by using its plain encoding result.
-  ///
-  /// @param value the value to hash.
-  /// @return hash result.
-  virtual uint64_t Hash(const FLBA* value, uint32_t len) const = 0;
-
-  virtual ~BloomFilter() {}
-
- protected:
-  // Hash strategy available for Bloom filter.
-  enum class HashStrategy : uint32_t { MURMUR3_X64_128 = 0 };
-
-  // Bloom filter algorithm.
-  enum class Algorithm : uint32_t { BLOCK = 0 };
-};
-
-// The BlockSplitBloomFilter is implemented using block-based Bloom filters from
-// Putze et al.'s "Cache-,Hash- and Space-Efficient Bloom filters". The basic idea is to
-// hash the item to a tiny Bloom filter which size fit a single cache line or smaller.
-//
-// This implementation sets 8 bits in each tiny Bloom filter. Each tiny Bloom
-// filter is 32 bytes to take advantage of 32-byte SIMD instructions.
-class BlockSplitBloomFilter : public BloomFilter {
- public:
-  /// The constructor of BlockSplitBloomFilter. It uses murmur3_x64_128 as hash function.
-  BlockSplitBloomFilter();
-
-  /// Initialize the BlockSplitBloomFilter. The range of num_bytes should be within
-  /// [kMinimumBloomFilterBytes, kMaximumBloomFilterBytes], it will be
-  /// rounded up/down to lower/upper bound if num_bytes is out of range and also
-  /// will be rounded up to a power of 2.
-  ///
-  /// @param num_bytes The number of bytes to store Bloom filter bitset.
-  void Init(uint32_t num_bytes);
-
-  /// Initialize the BlockSplitBloomFilter. It copies the bitset as underlying
-  /// bitset because the given bitset may not satisfy the 32-byte alignment requirement
-  /// which may lead to segfault when performing SIMD instructions. It is the caller's
-  /// responsibility to free the bitset passed in. This is used when reconstructing
-  /// a Bloom filter from a parquet file.
-  ///
-  /// @param bitset The given bitset to initialize the Bloom filter.
-  /// @param num_bytes  The number of bytes of given bitset.
-  void Init(const uint8_t* bitset, uint32_t num_bytes);
-
-  // Minimum Bloom filter size, it sets to 32 bytes to fit a tiny Bloom filter.
-  static constexpr uint32_t kMinimumBloomFilterBytes = 32;
-
-  /// Calculate optimal size according to the number of distinct values and false
-  /// positive probability.
-  ///
-  /// @param ndv The number of distinct values.
-  /// @param fpp The false positive probability.
-  /// @return it always return a value between kMinimumBloomFilterBytes and
-  /// kMaximumBloomFilterBytes, and the return value is always a power of 2
-  static uint32_t OptimalNumOfBits(uint32_t ndv, double fpp) {
-    DCHECK(fpp > 0.0 && fpp < 1.0);
-    const double m = -8.0 * ndv / log(1 - pow(fpp, 1.0 / 8));
-    uint32_t num_bits = static_cast<uint32_t>(m);
-
-    // Handle overflow.
-    if (m < 0 || m > kMaximumBloomFilterBytes << 3) {
-      num_bits = static_cast<uint32_t>(kMaximumBloomFilterBytes << 3);
-    }
-
-    // Round up to lower bound
-    if (num_bits < kMinimumBloomFilterBytes << 3) {
-      num_bits = kMinimumBloomFilterBytes << 3;
-    }
-
-    // Get next power of 2 if bits is not power of 2.
-    if ((num_bits & (num_bits - 1)) != 0) {
-      num_bits = static_cast<uint32_t>(::arrow::BitUtil::NextPower2(num_bits));
-    }
-
-    // Round down to upper bound
-    if (num_bits > kMaximumBloomFilterBytes << 3) {
-      num_bits = kMaximumBloomFilterBytes << 3;
-    }
-
-    return num_bits;
-  }
-
-  bool FindHash(uint64_t hash) const override;
-  void InsertHash(uint64_t hash) override;
-  void WriteTo(OutputStream* sink) const override;
-  uint32_t GetBitsetSize() const override { return num_bytes_; }
-  uint64_t Hash(int64_t value) const override { return hasher_->Hash(value); }
-  uint64_t Hash(float value) const override { return hasher_->Hash(value); }
-  uint64_t Hash(double value) const override { return hasher_->Hash(value); }
-  uint64_t Hash(const Int96* value) const override { return hasher_->Hash(value); }
-  uint64_t Hash(const ByteArray* value) const override { return hasher_->Hash(value); }
-  uint64_t Hash(int32_t value) const override { return hasher_->Hash(value); }
-  uint64_t Hash(const FLBA* value, uint32_t len) const override {
-    return hasher_->Hash(value, len);
-  }
-  /// Deserialize the Bloom filter from an input stream. It is used when reconstructing
-  /// a Bloom filter from a parquet filter.
-  ///
-  /// @param input_stream The input stream from which to construct the Bloom filter
-  /// @return The BlockSplitBloomFilter.
-  static BlockSplitBloomFilter Deserialize(InputStream* input_stream);
-
- private:
-  // Bytes in a tiny Bloom filter block.
-  static constexpr int kBytesPerFilterBlock = 32;
-
-  // The number of bits to be set in each tiny Bloom filter
-  static constexpr int kBitsSetPerBlock = 8;
-
-  // A mask structure used to set bits in each tiny Bloom filter.
-  struct BlockMask {
-    uint32_t item[kBitsSetPerBlock];
-  };
-
-  // The block-based algorithm needs eight odd SALT values to calculate eight indexes
-  // of bit to set, one bit in each 32-bit word.
-  static constexpr uint32_t SALT[kBitsSetPerBlock] = {
-      0x47b6137bU, 0x44974d91U, 0x8824ad5bU, 0xa2b7289dU,
-      0x705495c7U, 0x2df1424bU, 0x9efc4947U, 0x5c6bfb31U};
-
-  /// Set bits in mask array according to input key.
-  /// @param key the value to calculate mask values.
-  /// @param mask the mask array is used to set inside a block
-  void SetMask(uint32_t key, BlockMask& mask) const;
-
-  // Memory pool to allocate aligned buffer for bitset
-  ::arrow::MemoryPool* pool_;
-
-  // The underlying buffer of bitset.
-  std::shared_ptr<Buffer> data_;
-
-  // The number of bytes of Bloom filter bitset.
-  uint32_t num_bytes_;
-
-  // Hash strategy used in this Bloom filter.
-  HashStrategy hash_strategy_;
-
-  // Algorithm used in this Bloom filter.
-  Algorithm algorithm_;
-
-  // The hash pointer points to actual hash class used.
-  std::unique_ptr<Hasher> hasher_;
-};
-
-}  // namespace parquet
-
-#endif  // PARQUET_BLOOM_FILTER_H
diff --git a/src/parquet/column-io-benchmark.cc b/src/parquet/column-io-benchmark.cc
deleted file mode 100644
index a9a7530..0000000
--- a/src/parquet/column-io-benchmark.cc
+++ /dev/null
@@ -1,237 +0,0 @@
-// 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.
-
-#include "benchmark/benchmark.h"
-
-#include "parquet/column_reader.h"
-#include "parquet/column_writer.h"
-#include "parquet/file_reader.h"
-#include "parquet/parquet_types.h"
-#include "parquet/util/memory.h"
-
-namespace parquet {
-
-using schema::PrimitiveNode;
-
-namespace benchmark {
-
-std::unique_ptr<Int64Writer> BuildWriter(int64_t output_size, OutputStream* dst,
-                                         ColumnChunkMetaDataBuilder* metadata,
-                                         ColumnDescriptor* schema,
-                                         const WriterProperties* properties) {
-  std::unique_ptr<PageWriter> pager =
-      PageWriter::Open(dst, Compression::UNCOMPRESSED, metadata);
-  return std::unique_ptr<Int64Writer>(
-      new Int64Writer(metadata, std::move(pager), Encoding::PLAIN, properties));
-}
-
-std::shared_ptr<ColumnDescriptor> Int64Schema(Repetition::type repetition) {
-  auto node = PrimitiveNode::Make("int64", repetition, Type::INT64);
-  return std::make_shared<ColumnDescriptor>(node, repetition != Repetition::REQUIRED,
-                                            repetition == Repetition::REPEATED);
-}
-
-void SetBytesProcessed(::benchmark::State& state, Repetition::type repetition) {
-  int64_t bytes_processed = state.iterations() * state.range(0) * sizeof(int64_t);
-  if (repetition != Repetition::REQUIRED) {
-    bytes_processed += state.iterations() * state.range(0) * sizeof(int16_t);
-  }
-  if (repetition == Repetition::REPEATED) {
-    bytes_processed += state.iterations() * state.range(0) * sizeof(int16_t);
-  }
-  state.SetBytesProcessed(state.iterations() * state.range(0) * sizeof(int16_t));
-}
-
-template <Repetition::type repetition,
-          Compression::type codec = Compression::UNCOMPRESSED>
-static void BM_WriteInt64Column(::benchmark::State& state) {
-  format::ColumnChunk thrift_metadata;
-  std::vector<int64_t> values(state.range(0), 128);
-  std::vector<int16_t> definition_levels(state.range(0), 1);
-  std::vector<int16_t> repetition_levels(state.range(0), 0);
-  std::shared_ptr<ColumnDescriptor> schema = Int64Schema(repetition);
-  WriterProperties::Builder builder;
-  std::shared_ptr<WriterProperties> properties = builder.compression(codec)->build();
-  auto metadata = ColumnChunkMetaDataBuilder::Make(
-      properties, schema.get(), reinterpret_cast<uint8_t*>(&thrift_metadata));
-
-  while (state.KeepRunning()) {
-    InMemoryOutputStream stream;
-    std::unique_ptr<Int64Writer> writer = BuildWriter(
-        state.range(0), &stream, metadata.get(), schema.get(), properties.get());
-    writer->WriteBatch(values.size(), definition_levels.data(), repetition_levels.data(),
-                       values.data());
-    writer->Close();
-  }
-  SetBytesProcessed(state, repetition);
-}
-
-BENCHMARK_TEMPLATE(BM_WriteInt64Column, Repetition::REQUIRED)->Range(1024, 65536);
-
-BENCHMARK_TEMPLATE(BM_WriteInt64Column, Repetition::OPTIONAL)->Range(1024, 65536);
-
-BENCHMARK_TEMPLATE(BM_WriteInt64Column, Repetition::REPEATED)->Range(1024, 65536);
-
-BENCHMARK_TEMPLATE(BM_WriteInt64Column, Repetition::REQUIRED, Compression::SNAPPY)
-    ->Range(1024, 65536);
-BENCHMARK_TEMPLATE(BM_WriteInt64Column, Repetition::OPTIONAL, Compression::SNAPPY)
-    ->Range(1024, 65536);
-BENCHMARK_TEMPLATE(BM_WriteInt64Column, Repetition::REPEATED, Compression::SNAPPY)
-    ->Range(1024, 65536);
-
-BENCHMARK_TEMPLATE(BM_WriteInt64Column, Repetition::REQUIRED, Compression::LZ4)
-    ->Range(1024, 65536);
-BENCHMARK_TEMPLATE(BM_WriteInt64Column, Repetition::OPTIONAL, Compression::LZ4)
-    ->Range(1024, 65536);
-BENCHMARK_TEMPLATE(BM_WriteInt64Column, Repetition::REPEATED, Compression::LZ4)
-    ->Range(1024, 65536);
-
-BENCHMARK_TEMPLATE(BM_WriteInt64Column, Repetition::REQUIRED, Compression::ZSTD)
-    ->Range(1024, 65536);
-BENCHMARK_TEMPLATE(BM_WriteInt64Column, Repetition::OPTIONAL, Compression::ZSTD)
-    ->Range(1024, 65536);
-BENCHMARK_TEMPLATE(BM_WriteInt64Column, Repetition::REPEATED, Compression::ZSTD)
-    ->Range(1024, 65536);
-
-std::unique_ptr<Int64Reader> BuildReader(std::shared_ptr<Buffer>& buffer,
-                                         int64_t num_values, ColumnDescriptor* schema) {
-  std::unique_ptr<InMemoryInputStream> source(new InMemoryInputStream(buffer));
-  std::unique_ptr<PageReader> page_reader =
-      PageReader::Open(std::move(source), num_values, Compression::UNCOMPRESSED);
-  return std::unique_ptr<Int64Reader>(new Int64Reader(schema, std::move(page_reader)));
-}
-
-template <Repetition::type repetition,
-          Compression::type codec = Compression::UNCOMPRESSED>
-static void BM_ReadInt64Column(::benchmark::State& state) {
-  format::ColumnChunk thrift_metadata;
-  std::vector<int64_t> values(state.range(0), 128);
-  std::vector<int16_t> definition_levels(state.range(0), 1);
-  std::vector<int16_t> repetition_levels(state.range(0), 0);
-  std::shared_ptr<ColumnDescriptor> schema = Int64Schema(repetition);
-  WriterProperties::Builder builder;
-  std::shared_ptr<WriterProperties> properties = builder.compression(codec)->build();
-  auto metadata = ColumnChunkMetaDataBuilder::Make(
-      properties, schema.get(), reinterpret_cast<uint8_t*>(&thrift_metadata));
-
-  InMemoryOutputStream stream;
-  std::unique_ptr<Int64Writer> writer = BuildWriter(
-      state.range(0), &stream, metadata.get(), schema.get(), properties.get());
-  writer->WriteBatch(values.size(), definition_levels.data(), repetition_levels.data(),
-                     values.data());
-  writer->Close();
-
-  std::shared_ptr<Buffer> src = stream.GetBuffer();
-  std::vector<int64_t> values_out(state.range(1));
-  std::vector<int16_t> definition_levels_out(state.range(1));
-  std::vector<int16_t> repetition_levels_out(state.range(1));
-  while (state.KeepRunning()) {
-    std::unique_ptr<Int64Reader> reader = BuildReader(src, state.range(1), schema.get());
-    int64_t values_read = 0;
-    for (size_t i = 0; i < values.size(); i += values_read) {
-      reader->ReadBatch(values_out.size(), definition_levels_out.data(),
-                        repetition_levels_out.data(), values_out.data(), &values_read);
-    }
-  }
-  SetBytesProcessed(state, repetition);
-}
-
-BENCHMARK_TEMPLATE(BM_ReadInt64Column, Repetition::REQUIRED)
-    ->RangePair(1024, 65536, 1, 1024);
-
-BENCHMARK_TEMPLATE(BM_ReadInt64Column, Repetition::OPTIONAL)
-    ->RangePair(1024, 65536, 1, 1024);
-
-BENCHMARK_TEMPLATE(BM_ReadInt64Column, Repetition::REPEATED)
-    ->RangePair(1024, 65536, 1, 1024);
-
-BENCHMARK_TEMPLATE(BM_ReadInt64Column, Repetition::REQUIRED, Compression::SNAPPY)
-    ->RangePair(1024, 65536, 1, 1024);
-BENCHMARK_TEMPLATE(BM_ReadInt64Column, Repetition::OPTIONAL, Compression::SNAPPY)
-    ->RangePair(1024, 65536, 1, 1024);
-BENCHMARK_TEMPLATE(BM_ReadInt64Column, Repetition::REPEATED, Compression::SNAPPY)
-    ->RangePair(1024, 65536, 1, 1024);
-
-BENCHMARK_TEMPLATE(BM_ReadInt64Column, Repetition::REQUIRED, Compression::LZ4)
-    ->RangePair(1024, 65536, 1, 1024);
-BENCHMARK_TEMPLATE(BM_ReadInt64Column, Repetition::OPTIONAL, Compression::LZ4)
-    ->RangePair(1024, 65536, 1, 1024);
-BENCHMARK_TEMPLATE(BM_ReadInt64Column, Repetition::REPEATED, Compression::LZ4)
-    ->RangePair(1024, 65536, 1, 1024);
-
-BENCHMARK_TEMPLATE(BM_ReadInt64Column, Repetition::REQUIRED, Compression::ZSTD)
-    ->RangePair(1024, 65536, 1, 1024);
-BENCHMARK_TEMPLATE(BM_ReadInt64Column, Repetition::OPTIONAL, Compression::ZSTD)
-    ->RangePair(1024, 65536, 1, 1024);
-BENCHMARK_TEMPLATE(BM_ReadInt64Column, Repetition::REPEATED, Compression::ZSTD)
-    ->RangePair(1024, 65536, 1, 1024);
-
-static void BM_RleEncoding(::benchmark::State& state) {
-  std::vector<int16_t> levels(state.range(0), 0);
-  int64_t n = 0;
-  std::generate(levels.begin(), levels.end(),
-                [&state, &n] { return (n++ % state.range(1)) == 0; });
-  int16_t max_level = 1;
-  int64_t rle_size = LevelEncoder::MaxBufferSize(Encoding::RLE, max_level,
-                                                 static_cast<int>(levels.size()));
-  auto buffer_rle = AllocateBuffer();
-  PARQUET_THROW_NOT_OK(buffer_rle->Resize(rle_size));
-
-  while (state.KeepRunning()) {
-    LevelEncoder level_encoder;
-    level_encoder.Init(Encoding::RLE, max_level, static_cast<int>(levels.size()),
-                       buffer_rle->mutable_data(), static_cast<int>(buffer_rle->size()));
-    level_encoder.Encode(static_cast<int>(levels.size()), levels.data());
-  }
-  state.SetBytesProcessed(state.iterations() * state.range(0) * sizeof(int16_t));
-  state.SetItemsProcessed(state.iterations() * state.range(0));
-}
-
-BENCHMARK(BM_RleEncoding)->RangePair(1024, 65536, 1, 16);
-
-static void BM_RleDecoding(::benchmark::State& state) {
-  LevelEncoder level_encoder;
-  std::vector<int16_t> levels(state.range(0), 0);
-  int64_t n = 0;
-  std::generate(levels.begin(), levels.end(),
-                [&state, &n] { return (n++ % state.range(1)) == 0; });
-  int16_t max_level = 1;
-  int rle_size = LevelEncoder::MaxBufferSize(Encoding::RLE, max_level,
-                                             static_cast<int>(levels.size()));
-  auto buffer_rle = AllocateBuffer();
-  PARQUET_THROW_NOT_OK(buffer_rle->Resize(rle_size + sizeof(int32_t)));
-  level_encoder.Init(Encoding::RLE, max_level, static_cast<int>(levels.size()),
-                     buffer_rle->mutable_data() + sizeof(int32_t), rle_size);
-  level_encoder.Encode(static_cast<int>(levels.size()), levels.data());
-  reinterpret_cast<int32_t*>(buffer_rle->mutable_data())[0] = level_encoder.len();
-
-  while (state.KeepRunning()) {
-    LevelDecoder level_decoder;
-    level_decoder.SetData(Encoding::RLE, max_level, static_cast<int>(levels.size()),
-                          buffer_rle->data());
-    level_decoder.Decode(state.range(0), levels.data());
-  }
-
-  state.SetBytesProcessed(state.iterations() * state.range(0) * sizeof(int16_t));
-  state.SetItemsProcessed(state.iterations() * state.range(0));
-}
-
-BENCHMARK(BM_RleDecoding)->RangePair(1024, 65536, 1, 16);
-
-}  // namespace benchmark
-
-}  // namespace parquet
diff --git a/src/parquet/column_page.h b/src/parquet/column_page.h
deleted file mode 100644
index c34eee7..0000000
--- a/src/parquet/column_page.h
+++ /dev/null
@@ -1,173 +0,0 @@
-// 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.
-
-// This module defines an abstract interface for iterating through pages in a
-// Parquet column chunk within a row group. It could be extended in the future
-// to iterate through all data pages in all chunks in a file.
-
-#ifndef PARQUET_COLUMN_PAGE_H
-#define PARQUET_COLUMN_PAGE_H
-
-#include <cstdint>
-#include <memory>
-#include <string>
-
-#include "parquet/statistics.h"
-#include "parquet/types.h"
-#include "parquet/util/memory.h"
-
-namespace parquet {
-
-// TODO: Parallel processing is not yet safe because of memory-ownership
-// semantics (the PageReader may or may not own the memory referenced by a
-// page)
-//
-// TODO(wesm): In the future Parquet implementations may store the crc code
-// in format::PageHeader. parquet-mr currently does not, so we also skip it
-// here, both on the read and write path
-class Page {
- public:
-  Page(const std::shared_ptr<Buffer>& buffer, PageType::type type)
-      : buffer_(buffer), type_(type) {}
-
-  PageType::type type() const { return type_; }
-
-  std::shared_ptr<Buffer> buffer() const { return buffer_; }
-
-  // @returns: a pointer to the page's data
-  const uint8_t* data() const { return buffer_->data(); }
-
-  // @returns: the total size in bytes of the page's data buffer
-  int32_t size() const { return static_cast<int32_t>(buffer_->size()); }
-
- private:
-  std::shared_ptr<Buffer> buffer_;
-  PageType::type type_;
-};
-
-class DataPage : public Page {
- public:
-  DataPage(const std::shared_ptr<Buffer>& buffer, int32_t num_values,
-           Encoding::type encoding, Encoding::type definition_level_encoding,
-           Encoding::type repetition_level_encoding,
-           const EncodedStatistics& statistics = EncodedStatistics())
-      : Page(buffer, PageType::DATA_PAGE),
-        num_values_(num_values),
-        encoding_(encoding),
-        definition_level_encoding_(definition_level_encoding),
-        repetition_level_encoding_(repetition_level_encoding),
-        statistics_(statistics) {}
-
-  int32_t num_values() const { return num_values_; }
-
-  Encoding::type encoding() const { return encoding_; }
-
-  Encoding::type repetition_level_encoding() const { return repetition_level_encoding_; }
-
-  Encoding::type definition_level_encoding() const { return definition_level_encoding_; }
-
-  const EncodedStatistics& statistics() const { return statistics_; }
-
- private:
-  int32_t num_values_;
-  Encoding::type encoding_;
-  Encoding::type definition_level_encoding_;
-  Encoding::type repetition_level_encoding_;
-  EncodedStatistics statistics_;
-};
-
-class CompressedDataPage : public DataPage {
- public:
-  CompressedDataPage(const std::shared_ptr<Buffer>& buffer, int32_t num_values,
-                     Encoding::type encoding, Encoding::type definition_level_encoding,
-                     Encoding::type repetition_level_encoding, int64_t uncompressed_size,
-                     const EncodedStatistics& statistics = EncodedStatistics())
-      : DataPage(buffer, num_values, encoding, definition_level_encoding,
-                 repetition_level_encoding, statistics),
-        uncompressed_size_(uncompressed_size) {}
-
-  int64_t uncompressed_size() const { return uncompressed_size_; }
-
- private:
-  int64_t uncompressed_size_;
-};
-
-class DataPageV2 : public Page {
- public:
-  DataPageV2(const std::shared_ptr<Buffer>& buffer, int32_t num_values, int32_t num_nulls,
-             int32_t num_rows, Encoding::type encoding,
-             int32_t definition_levels_byte_length, int32_t repetition_levels_byte_length,
-             bool is_compressed = false)
-      : Page(buffer, PageType::DATA_PAGE_V2),
-        num_values_(num_values),
-        num_nulls_(num_nulls),
-        num_rows_(num_rows),
-        encoding_(encoding),
-        definition_levels_byte_length_(definition_levels_byte_length),
-        repetition_levels_byte_length_(repetition_levels_byte_length),
-        is_compressed_(is_compressed) {}
-
-  int32_t num_values() const { return num_values_; }
-
-  int32_t num_nulls() const { return num_nulls_; }
-
-  int32_t num_rows() const { return num_rows_; }
-
-  Encoding::type encoding() const { return encoding_; }
-
-  int32_t definition_levels_byte_length() const { return definition_levels_byte_length_; }
-
-  int32_t repetition_levels_byte_length() const { return repetition_levels_byte_length_; }
-
-  bool is_compressed() const { return is_compressed_; }
-
- private:
-  int32_t num_values_;
-  int32_t num_nulls_;
-  int32_t num_rows_;
-  Encoding::type encoding_;
-  int32_t definition_levels_byte_length_;
-  int32_t repetition_levels_byte_length_;
-  bool is_compressed_;
-
-  // TODO(wesm): format::DataPageHeaderV2.statistics
-};
-
-class DictionaryPage : public Page {
- public:
-  DictionaryPage(const std::shared_ptr<Buffer>& buffer, int32_t num_values,
-                 Encoding::type encoding, bool is_sorted = false)
-      : Page(buffer, PageType::DICTIONARY_PAGE),
-        num_values_(num_values),
-        encoding_(encoding),
-        is_sorted_(is_sorted) {}
-
-  int32_t num_values() const { return num_values_; }
-
-  Encoding::type encoding() const { return encoding_; }
-
-  bool is_sorted() const { return is_sorted_; }
-
- private:
-  int32_t num_values_;
-  Encoding::type encoding_;
-  bool is_sorted_;
-};
-
-}  // namespace parquet
-
-#endif  // PARQUET_COLUMN_PAGE_H
diff --git a/src/parquet/column_reader-test.cc b/src/parquet/column_reader-test.cc
deleted file mode 100644
index 273b302..0000000
--- a/src/parquet/column_reader-test.cc
+++ /dev/null
@@ -1,390 +0,0 @@
-// 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.
-
-#include <gtest/gtest.h>
-
-#include <algorithm>
-#include <cstdint>
-#include <cstdlib>
-#include <limits>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "parquet/column_page.h"
-#include "parquet/column_reader.h"
-#include "parquet/schema.h"
-#include "parquet/test-util.h"
-#include "parquet/types.h"
-#include "parquet/util/test-common.h"
-
-using std::shared_ptr;
-using std::string;
-using std::vector;
-
-namespace parquet {
-
-using schema::NodePtr;
-
-namespace test {
-
-template <typename T>
-static inline bool vector_equal_with_def_levels(const vector<T>& left,
-                                                const vector<int16_t>& def_levels,
-                                                int16_t max_def_levels,
-                                                int16_t max_rep_levels,
-                                                const vector<T>& right) {
-  size_t i_left = 0;
-  size_t i_right = 0;
-  for (size_t i = 0; i < def_levels.size(); i++) {
-    if (def_levels[i] == max_def_levels) {
-      // Compare
-      if (left[i_left] != right[i_right]) {
-        std::cerr << "index " << i << " left was " << left[i_left] << " right was "
-                  << right[i] << std::endl;
-        return false;
-      }
-      i_left++;
-      i_right++;
-    } else if (def_levels[i] == (max_def_levels - 1)) {
-      // Null entry on the lowest nested level
-      i_right++;
-    } else if (def_levels[i] < (max_def_levels - 1)) {
-      // Null entry on a higher nesting level, only supported for non-repeating data
-      if (max_rep_levels == 0) {
-        i_right++;
-      }
-    }
-  }
-
-  return true;
-}
-
-class TestPrimitiveReader : public ::testing::Test {
- public:
-  void InitReader(const ColumnDescriptor* d) {
-    std::unique_ptr<PageReader> pager_;
-    pager_.reset(new test::MockPageReader(pages_));
-    reader_ = ColumnReader::Make(d, std::move(pager_));
-  }
-
-  void CheckResults() {
-    vector<int32_t> vresult(num_values_, -1);
-    vector<int16_t> dresult(num_levels_, -1);
-    vector<int16_t> rresult(num_levels_, -1);
-    int64_t values_read = 0;
-    int total_values_read = 0;
-    int batch_actual = 0;
-
-    Int32Reader* reader = static_cast<Int32Reader*>(reader_.get());
-    int32_t batch_size = 8;
-    int batch = 0;
-    // This will cover both the cases
-    // 1) batch_size < page_size (multiple ReadBatch from a single page)
-    // 2) batch_size > page_size (BatchRead limits to a single page)
-    do {
-      batch = static_cast<int>(reader->ReadBatch(
-          batch_size, &dresult[0] + batch_actual, &rresult[0] + batch_actual,
-          &vresult[0] + total_values_read, &values_read));
-      total_values_read += static_cast<int>(values_read);
-      batch_actual += batch;
-      batch_size = std::max(batch_size * 2, 4096);
-    } while (batch > 0);
-
-    ASSERT_EQ(num_levels_, batch_actual);
-    ASSERT_EQ(num_values_, total_values_read);
-    ASSERT_TRUE(vector_equal(values_, vresult));
-    if (max_def_level_ > 0) {
-      ASSERT_TRUE(vector_equal(def_levels_, dresult));
-    }
-    if (max_rep_level_ > 0) {
-      ASSERT_TRUE(vector_equal(rep_levels_, rresult));
-    }
-    // catch improper writes at EOS
-    batch_actual =
-        static_cast<int>(reader->ReadBatch(5, nullptr, nullptr, nullptr, &values_read));
-    ASSERT_EQ(0, batch_actual);
-    ASSERT_EQ(0, values_read);
-  }
-
-  void CheckResultsSpaced() {
-    vector<int32_t> vresult(num_levels_, -1);
-    vector<int16_t> dresult(num_levels_, -1);
-    vector<int16_t> rresult(num_levels_, -1);
-    vector<uint8_t> valid_bits(num_levels_, 255);
-    int total_values_read = 0;
-    int batch_actual = 0;
-    int levels_actual = 0;
-    int64_t null_count = -1;
-    int64_t levels_read = 0;
-    int64_t values_read;
-
-    Int32Reader* reader = static_cast<Int32Reader*>(reader_.get());
-    int32_t batch_size = 8;
-    int batch = 0;
-    // This will cover both the cases
-    // 1) batch_size < page_size (multiple ReadBatch from a single page)
-    // 2) batch_size > page_size (BatchRead limits to a single page)
-    do {
-      batch = static_cast<int>(reader->ReadBatchSpaced(
-          batch_size, dresult.data() + levels_actual, rresult.data() + levels_actual,
-          vresult.data() + batch_actual, valid_bits.data() + batch_actual, 0,
-          &levels_read, &values_read, &null_count));
-      total_values_read += batch - static_cast<int>(null_count);
-      batch_actual += batch;
-      levels_actual += static_cast<int>(levels_read);
-      batch_size = std::max(batch_size * 2, 4096);
-    } while ((batch > 0) || (levels_read > 0));
-
-    ASSERT_EQ(num_levels_, levels_actual);
-    ASSERT_EQ(num_values_, total_values_read);
-    if (max_def_level_ > 0) {
-      ASSERT_TRUE(vector_equal(def_levels_, dresult));
-      ASSERT_TRUE(vector_equal_with_def_levels(values_, dresult, max_def_level_,
-                                               max_rep_level_, vresult));
-    } else {
-      ASSERT_TRUE(vector_equal(values_, vresult));
-    }
-    if (max_rep_level_ > 0) {
-      ASSERT_TRUE(vector_equal(rep_levels_, rresult));
-    }
-    // catch improper writes at EOS
-    batch_actual = static_cast<int>(
-        reader->ReadBatchSpaced(5, nullptr, nullptr, nullptr, valid_bits.data(), 0,
-                                &levels_read, &values_read, &null_count));
-    ASSERT_EQ(0, batch_actual);
-    ASSERT_EQ(0, null_count);
-  }
-
-  void Clear() {
-    values_.clear();
-    def_levels_.clear();
-    rep_levels_.clear();
-    pages_.clear();
-    reader_.reset();
-  }
-
-  void ExecutePlain(int num_pages, int levels_per_page, const ColumnDescriptor* d) {
-    num_values_ =
-        MakePages<Int32Type>(d, num_pages, levels_per_page, def_levels_, rep_levels_,
-                             values_, data_buffer_, pages_, Encoding::PLAIN);
-    num_levels_ = num_pages * levels_per_page;
-    InitReader(d);
-    CheckResults();
-    Clear();
-
-    num_values_ =
-        MakePages<Int32Type>(d, num_pages, levels_per_page, def_levels_, rep_levels_,
-                             values_, data_buffer_, pages_, Encoding::PLAIN);
-    num_levels_ = num_pages * levels_per_page;
-    InitReader(d);
-    CheckResultsSpaced();
-    Clear();
-  }
-
-  void ExecuteDict(int num_pages, int levels_per_page, const ColumnDescriptor* d) {
-    num_values_ =
-        MakePages<Int32Type>(d, num_pages, levels_per_page, def_levels_, rep_levels_,
-                             values_, data_buffer_, pages_, Encoding::RLE_DICTIONARY);
-    num_levels_ = num_pages * levels_per_page;
-    InitReader(d);
-    CheckResults();
-    Clear();
-
-    num_values_ =
-        MakePages<Int32Type>(d, num_pages, levels_per_page, def_levels_, rep_levels_,
-                             values_, data_buffer_, pages_, Encoding::RLE_DICTIONARY);
-    num_levels_ = num_pages * levels_per_page;
-    InitReader(d);
-    CheckResultsSpaced();
-    Clear();
-  }
-
- protected:
-  int num_levels_;
-  int num_values_;
-  int16_t max_def_level_;
-  int16_t max_rep_level_;
-  vector<shared_ptr<Page>> pages_;
-  std::shared_ptr<ColumnReader> reader_;
-  vector<int32_t> values_;
-  vector<int16_t> def_levels_;
-  vector<int16_t> rep_levels_;
-  vector<uint8_t> data_buffer_;  // For BA and FLBA
-};
-
-TEST_F(TestPrimitiveReader, TestInt32FlatRequired) {
-  int levels_per_page = 100;
-  int num_pages = 50;
-  max_def_level_ = 0;
-  max_rep_level_ = 0;
-  NodePtr type = schema::Int32("a", Repetition::REQUIRED);
-  const ColumnDescriptor descr(type, max_def_level_, max_rep_level_);
-  ASSERT_NO_FATAL_FAILURE(ExecutePlain(num_pages, levels_per_page, &descr));
-  ASSERT_NO_FATAL_FAILURE(ExecuteDict(num_pages, levels_per_page, &descr));
-}
-
-TEST_F(TestPrimitiveReader, TestInt32FlatOptional) {
-  int levels_per_page = 100;
-  int num_pages = 50;
-  max_def_level_ = 4;
-  max_rep_level_ = 0;
-  NodePtr type = schema::Int32("b", Repetition::OPTIONAL);
-  const ColumnDescriptor descr(type, max_def_level_, max_rep_level_);
-  ASSERT_NO_FATAL_FAILURE(ExecutePlain(num_pages, levels_per_page, &descr));
-  ASSERT_NO_FATAL_FAILURE(ExecuteDict(num_pages, levels_per_page, &descr));
-}
-
-TEST_F(TestPrimitiveReader, TestInt32FlatRepeated) {
-  int levels_per_page = 100;
-  int num_pages = 50;
-  max_def_level_ = 4;
-  max_rep_level_ = 2;
-  NodePtr type = schema::Int32("c", Repetition::REPEATED);
-  const ColumnDescriptor descr(type, max_def_level_, max_rep_level_);
-  ASSERT_NO_FATAL_FAILURE(ExecutePlain(num_pages, levels_per_page, &descr));
-  ASSERT_NO_FATAL_FAILURE(ExecuteDict(num_pages, levels_per_page, &descr));
-}
-
-TEST_F(TestPrimitiveReader, TestInt32FlatRequiredSkip) {
-  int levels_per_page = 100;
-  int num_pages = 5;
-  max_def_level_ = 0;
-  max_rep_level_ = 0;
-  NodePtr type = schema::Int32("b", Repetition::REQUIRED);
-  const ColumnDescriptor descr(type, max_def_level_, max_rep_level_);
-  MakePages<Int32Type>(&descr, num_pages, levels_per_page, def_levels_, rep_levels_,
-                       values_, data_buffer_, pages_, Encoding::PLAIN);
-  InitReader(&descr);
-  vector<int32_t> vresult(levels_per_page / 2, -1);
-  vector<int16_t> dresult(levels_per_page / 2, -1);
-  vector<int16_t> rresult(levels_per_page / 2, -1);
-
-  Int32Reader* reader = static_cast<Int32Reader*>(reader_.get());
-  int64_t values_read = 0;
-
-  // 1) skip_size > page_size (multiple pages skipped)
-  // Skip first 2 pages
-  int64_t levels_skipped = reader->Skip(2 * levels_per_page);
-  ASSERT_EQ(2 * levels_per_page, levels_skipped);
-  // Read half a page
-  reader->ReadBatch(levels_per_page / 2, dresult.data(), rresult.data(), vresult.data(),
-                    &values_read);
-  vector<int32_t> sub_values(
-      values_.begin() + 2 * levels_per_page,
-      values_.begin() + static_cast<int>(2.5 * static_cast<double>(levels_per_page)));
-  ASSERT_TRUE(vector_equal(sub_values, vresult));
-
-  // 2) skip_size == page_size (skip across two pages)
-  levels_skipped = reader->Skip(levels_per_page);
-  ASSERT_EQ(levels_per_page, levels_skipped);
-  // Read half a page
-  reader->ReadBatch(levels_per_page / 2, dresult.data(), rresult.data(), vresult.data(),
-                    &values_read);
-  sub_values.clear();
-  sub_values.insert(
-      sub_values.end(),
-      values_.begin() + static_cast<int>(3.5 * static_cast<double>(levels_per_page)),
-      values_.begin() + 4 * levels_per_page);
-  ASSERT_TRUE(vector_equal(sub_values, vresult));
-
-  // 3) skip_size < page_size (skip limited to a single page)
-  // Skip half a page
-  levels_skipped = reader->Skip(levels_per_page / 2);
-  ASSERT_EQ(0.5 * levels_per_page, levels_skipped);
-  // Read half a page
-  reader->ReadBatch(levels_per_page / 2, dresult.data(), rresult.data(), vresult.data(),
-                    &values_read);
-  sub_values.clear();
-  sub_values.insert(
-      sub_values.end(),
-      values_.begin() + static_cast<int>(4.5 * static_cast<double>(levels_per_page)),
-      values_.end());
-  ASSERT_TRUE(vector_equal(sub_values, vresult));
-
-  values_.clear();
-  def_levels_.clear();
-  rep_levels_.clear();
-  pages_.clear();
-  reader_.reset();
-}
-
-TEST_F(TestPrimitiveReader, TestDictionaryEncodedPages) {
-  max_def_level_ = 0;
-  max_rep_level_ = 0;
-  NodePtr type = schema::Int32("a", Repetition::REQUIRED);
-  const ColumnDescriptor descr(type, max_def_level_, max_rep_level_);
-  shared_ptr<ResizableBuffer> dummy = AllocateBuffer();
-
-  shared_ptr<DictionaryPage> dict_page =
-      std::make_shared<DictionaryPage>(dummy, 0, Encoding::PLAIN);
-  shared_ptr<DataPage> data_page = MakeDataPage<Int32Type>(
-      &descr, {}, 0, Encoding::RLE_DICTIONARY, {}, 0, {}, 0, {}, 0);
-  pages_.push_back(dict_page);
-  pages_.push_back(data_page);
-  InitReader(&descr);
-  // Tests Dict : PLAIN, Data : RLE_DICTIONARY
-  ASSERT_NO_THROW(reader_->HasNext());
-  pages_.clear();
-
-  dict_page = std::make_shared<DictionaryPage>(dummy, 0, Encoding::PLAIN_DICTIONARY);
-  data_page = MakeDataPage<Int32Type>(&descr, {}, 0, Encoding::PLAIN_DICTIONARY, {}, 0,
-                                      {}, 0, {}, 0);
-  pages_.push_back(dict_page);
-  pages_.push_back(data_page);
-  InitReader(&descr);
-  // Tests Dict : PLAIN_DICTIONARY, Data : PLAIN_DICTIONARY
-  ASSERT_NO_THROW(reader_->HasNext());
-  pages_.clear();
-
-  data_page = MakeDataPage<Int32Type>(&descr, {}, 0, Encoding::RLE_DICTIONARY, {}, 0, {},
-                                      0, {}, 0);
-  pages_.push_back(data_page);
-  InitReader(&descr);
-  // Tests dictionary page must occur before data page
-  ASSERT_THROW(reader_->HasNext(), ParquetException);
-  pages_.clear();
-
-  dict_page = std::make_shared<DictionaryPage>(dummy, 0, Encoding::DELTA_BYTE_ARRAY);
-  pages_.push_back(dict_page);
-  InitReader(&descr);
-  // Tests only RLE_DICTIONARY is supported
-  ASSERT_THROW(reader_->HasNext(), ParquetException);
-  pages_.clear();
-
-  shared_ptr<DictionaryPage> dict_page1 =
-      std::make_shared<DictionaryPage>(dummy, 0, Encoding::PLAIN_DICTIONARY);
-  shared_ptr<DictionaryPage> dict_page2 =
-      std::make_shared<DictionaryPage>(dummy, 0, Encoding::PLAIN);
-  pages_.push_back(dict_page1);
-  pages_.push_back(dict_page2);
-  InitReader(&descr);
-  // Column cannot have more than one dictionary
-  ASSERT_THROW(reader_->HasNext(), ParquetException);
-  pages_.clear();
-
-  data_page = MakeDataPage<Int32Type>(&descr, {}, 0, Encoding::DELTA_BYTE_ARRAY, {}, 0,
-                                      {}, 0, {}, 0);
-  pages_.push_back(data_page);
-  InitReader(&descr);
-  // unsupported encoding
-  ASSERT_THROW(reader_->HasNext(), ParquetException);
-  pages_.clear();
-}
-
-}  // namespace test
-}  // namespace parquet
diff --git a/src/parquet/column_reader.cc b/src/parquet/column_reader.cc
deleted file mode 100644
index 28d0dcb..0000000
--- a/src/parquet/column_reader.cc
+++ /dev/null
@@ -1,475 +0,0 @@
-// 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.
-
-#include "parquet/column_reader.h"
-
-#include <algorithm>
-#include <cstdint>
-#include <memory>
-
-#include <arrow/buffer.h>
-#include <arrow/memory_pool.h>
-#include <arrow/util/bit-util.h>
-#include <arrow/util/compression.h>
-#include <arrow/util/rle-encoding.h>
-
-#include "parquet/column_page.h"
-#include "parquet/encoding-internal.h"
-#include "parquet/parquet_types.h"
-#include "parquet/properties.h"
-#include "parquet/thrift.h"
-
-using arrow::MemoryPool;
-
-namespace parquet {
-
-LevelDecoder::LevelDecoder() : num_values_remaining_(0) {}
-
-LevelDecoder::~LevelDecoder() {}
-
-int LevelDecoder::SetData(Encoding::type encoding, int16_t max_level,
-                          int num_buffered_values, const uint8_t* data) {
-  int32_t num_bytes = 0;
-  encoding_ = encoding;
-  num_values_remaining_ = num_buffered_values;
-  bit_width_ = BitUtil::Log2(max_level + 1);
-  switch (encoding) {
-    case Encoding::RLE: {
-      num_bytes = *reinterpret_cast<const int32_t*>(data);
-      const uint8_t* decoder_data = data + sizeof(int32_t);
-      if (!rle_decoder_) {
-        rle_decoder_.reset(new ::arrow::RleDecoder(decoder_data, num_bytes, bit_width_));
-      } else {
-        rle_decoder_->Reset(decoder_data, num_bytes, bit_width_);
-      }
-      return static_cast<int>(sizeof(int32_t)) + num_bytes;
-    }
-    case Encoding::BIT_PACKED: {
-      num_bytes =
-          static_cast<int32_t>(BitUtil::BytesForBits(num_buffered_values * bit_width_));
-      if (!bit_packed_decoder_) {
-        bit_packed_decoder_.reset(new ::arrow::BitReader(data, num_bytes));
-      } else {
-        bit_packed_decoder_->Reset(data, num_bytes);
-      }
-      return num_bytes;
-    }
-    default:
-      throw ParquetException("Unknown encoding type for levels.");
-  }
-  return -1;
-}
-
-int LevelDecoder::Decode(int batch_size, int16_t* levels) {
-  int num_decoded = 0;
-
-  int num_values = std::min(num_values_remaining_, batch_size);
-  if (encoding_ == Encoding::RLE) {
-    num_decoded = rle_decoder_->GetBatch(levels, num_values);
-  } else {
-    num_decoded = bit_packed_decoder_->GetBatch(bit_width_, levels, num_values);
-  }
-  num_values_remaining_ -= num_decoded;
-  return num_decoded;
-}
-
-ReaderProperties default_reader_properties() {
-  static ReaderProperties default_reader_properties;
-  return default_reader_properties;
-}
-
-// ----------------------------------------------------------------------
-// SerializedPageReader deserializes Thrift metadata and pages that have been
-// assembled in a serialized stream for storing in a Parquet files
-
-// This subclass delimits pages appearing in a serialized stream, each preceded
-// by a serialized Thrift format::PageHeader indicating the type of each page
-// and the page metadata.
-class SerializedPageReader : public PageReader {
- public:
-  SerializedPageReader(std::unique_ptr<InputStream> stream, int64_t total_num_rows,
-                       Compression::type codec, ::arrow::MemoryPool* pool)
-      : stream_(std::move(stream)),
-        decompression_buffer_(AllocateBuffer(pool, 0)),
-        seen_num_rows_(0),
-        total_num_rows_(total_num_rows) {
-    max_page_header_size_ = kDefaultMaxPageHeaderSize;
-    decompressor_ = GetCodecFromArrow(codec);
-  }
-
-  // Implement the PageReader interface
-  std::shared_ptr<Page> NextPage() override;
-
-  void set_max_page_header_size(uint32_t size) override { max_page_header_size_ = size; }
-
- private:
-  std::unique_ptr<InputStream> stream_;
-
-  format::PageHeader current_page_header_;
-  std::shared_ptr<Page> current_page_;
-
-  // Compression codec to use.
-  std::unique_ptr<::arrow::Codec> decompressor_;
-  std::shared_ptr<ResizableBuffer> decompression_buffer_;
-
-  // Maximum allowed page size
-  uint32_t max_page_header_size_;
-
-  // Number of rows read in data pages so far
-  int64_t seen_num_rows_;
-
-  // Number of rows in all the data pages
-  int64_t total_num_rows_;
-};
-
-std::shared_ptr<Page> SerializedPageReader::NextPage() {
-  // Loop here because there may be unhandled page types that we skip until
-  // finding a page that we do know what to do with
-  while (seen_num_rows_ < total_num_rows_) {
-    int64_t bytes_read = 0;
-    int64_t bytes_available = 0;
-    uint32_t header_size = 0;
-    const uint8_t* buffer;
-    uint32_t allowed_page_size = kDefaultPageHeaderSize;
-
-    // Page headers can be very large because of page statistics
-    // We try to deserialize a larger buffer progressively
-    // until a maximum allowed header limit
-    while (true) {
-      buffer = stream_->Peek(allowed_page_size, &bytes_available);
-      if (bytes_available == 0) {
-        return std::shared_ptr<Page>(nullptr);
-      }
-
-      // This gets used, then set by DeserializeThriftMsg
-      header_size = static_cast<uint32_t>(bytes_available);
-      try {
-        DeserializeThriftMsg(buffer, &header_size, &current_page_header_);
-        break;
-      } catch (std::exception& e) {
-        // Failed to deserialize. Double the allowed page header size and try again
-        std::stringstream ss;
-        ss << e.what();
-        allowed_page_size *= 2;
-        if (allowed_page_size > max_page_header_size_) {
-          ss << "Deserializing page header failed.\n";
-          throw ParquetException(ss.str());
-        }
-      }
-    }
-    // Advance the stream offset
-    stream_->Advance(header_size);
-
-    int compressed_len = current_page_header_.compressed_page_size;
-    int uncompressed_len = current_page_header_.uncompressed_page_size;
-
-    // Read the compressed data page.
-    buffer = stream_->Read(compressed_len, &bytes_read);
-    if (bytes_read != compressed_len) {
-      std::stringstream ss;
-      ss << "Page was smaller (" << bytes_read << ") than expected (" << compressed_len
-         << ")";
-      ParquetException::EofException(ss.str());
-    }
-
-    // Uncompress it if we need to
-    if (decompressor_ != nullptr) {
-      // Grow the uncompressed buffer if we need to.
-      if (uncompressed_len > static_cast<int>(decompression_buffer_->size())) {
-        PARQUET_THROW_NOT_OK(decompression_buffer_->Resize(uncompressed_len, false));
-      }
-      PARQUET_THROW_NOT_OK(
-          decompressor_->Decompress(compressed_len, buffer, uncompressed_len,
-                                    decompression_buffer_->mutable_data()));
-      buffer = decompression_buffer_->data();
-    }
-
-    auto page_buffer = std::make_shared<Buffer>(buffer, uncompressed_len);
-
-    if (current_page_header_.type == format::PageType::DICTIONARY_PAGE) {
-      const format::DictionaryPageHeader& dict_header =
-          current_page_header_.dictionary_page_header;
-
-      bool is_sorted = dict_header.__isset.is_sorted ? dict_header.is_sorted : false;
-
-      return std::make_shared<DictionaryPage>(page_buffer, dict_header.num_values,
-                                              FromThrift(dict_header.encoding),
-                                              is_sorted);
-    } else if (current_page_header_.type == format::PageType::DATA_PAGE) {
-      const format::DataPageHeader& header = current_page_header_.data_page_header;
-
-      EncodedStatistics page_statistics;
-      if (header.__isset.statistics) {
-        const format::Statistics& stats = header.statistics;
-        if (stats.__isset.max) {
-          page_statistics.set_max(stats.max);
-        }
-        if (stats.__isset.min) {
-          page_statistics.set_min(stats.min);
-        }
-        if (stats.__isset.null_count) {
-          page_statistics.set_null_count(stats.null_count);
-        }
-        if (stats.__isset.distinct_count) {
-          page_statistics.set_distinct_count(stats.distinct_count);
-        }
-      }
-
-      seen_num_rows_ += header.num_values;
-
-      return std::make_shared<DataPage>(
-          page_buffer, header.num_values, FromThrift(header.encoding),
-          FromThrift(header.definition_level_encoding),
-          FromThrift(header.repetition_level_encoding), page_statistics);
-    } else if (current_page_header_.type == format::PageType::DATA_PAGE_V2) {
-      const format::DataPageHeaderV2& header = current_page_header_.data_page_header_v2;
-      bool is_compressed = header.__isset.is_compressed ? header.is_compressed : false;
-
-      seen_num_rows_ += header.num_values;
-
-      return std::make_shared<DataPageV2>(
-          page_buffer, header.num_values, header.num_nulls, header.num_rows,
-          FromThrift(header.encoding), header.definition_levels_byte_length,
-          header.repetition_levels_byte_length, is_compressed);
-    } else {
-      // We don't know what this page type is. We're allowed to skip non-data
-      // pages.
-      continue;
-    }
-  }
-  return std::shared_ptr<Page>(nullptr);
-}
-
-std::unique_ptr<PageReader> PageReader::Open(std::unique_ptr<InputStream> stream,
-                                             int64_t total_num_rows,
-                                             Compression::type codec,
-                                             ::arrow::MemoryPool* pool) {
-  return std::unique_ptr<PageReader>(
-      new SerializedPageReader(std::move(stream), total_num_rows, codec, pool));
-}
-
-// ----------------------------------------------------------------------
-
-ColumnReader::ColumnReader(const ColumnDescriptor* descr,
-                           std::unique_ptr<PageReader> pager, MemoryPool* pool)
-    : descr_(descr),
-      pager_(std::move(pager)),
-      num_buffered_values_(0),
-      num_decoded_values_(0),
-      pool_(pool) {}
-
-ColumnReader::~ColumnReader() {}
-
-template <typename DType>
-void TypedColumnReader<DType>::ConfigureDictionary(const DictionaryPage* page) {
-  int encoding = static_cast<int>(page->encoding());
-  if (page->encoding() == Encoding::PLAIN_DICTIONARY ||
-      page->encoding() == Encoding::PLAIN) {
-    encoding = static_cast<int>(Encoding::RLE_DICTIONARY);
-  }
-
-  auto it = decoders_.find(encoding);
-  if (it != decoders_.end()) {
-    throw ParquetException("Column cannot have more than one dictionary.");
-  }
-
-  if (page->encoding() == Encoding::PLAIN_DICTIONARY ||
-      page->encoding() == Encoding::PLAIN) {
-    PlainDecoder<DType> dictionary(descr_);
-    dictionary.SetData(page->num_values(), page->data(), page->size());
-
-    // The dictionary is fully decoded during DictionaryDecoder::Init, so the
-    // DictionaryPage buffer is no longer required after this step
-    //
-    // TODO(wesm): investigate whether this all-or-nothing decoding of the
-    // dictionary makes sense and whether performance can be improved
-
-    auto decoder = std::make_shared<DictionaryDecoder<DType>>(descr_, pool_);
-    decoder->SetDict(&dictionary);
-    decoders_[encoding] = decoder;
-  } else {
-    ParquetException::NYI("only plain dictionary encoding has been implemented");
-  }
-
-  current_decoder_ = decoders_[encoding].get();
-}
-
-// PLAIN_DICTIONARY is deprecated but used to be used as a dictionary index
-// encoding.
-static bool IsDictionaryIndexEncoding(const Encoding::type& e) {
-  return e == Encoding::RLE_DICTIONARY || e == Encoding::PLAIN_DICTIONARY;
-}
-
-template <typename DType>
-bool TypedColumnReader<DType>::ReadNewPage() {
-  // Loop until we find the next data page.
-  const uint8_t* buffer;
-
-  while (true) {
-    current_page_ = pager_->NextPage();
-    if (!current_page_) {
-      // EOS
-      return false;
-    }
-
-    if (current_page_->type() == PageType::DICTIONARY_PAGE) {
-      ConfigureDictionary(static_cast<const DictionaryPage*>(current_page_.get()));
-      continue;
-    } else if (current_page_->type() == PageType::DATA_PAGE) {
-      const DataPage* page = static_cast<const DataPage*>(current_page_.get());
-
-      // Read a data page.
-      num_buffered_values_ = page->num_values();
-
-      // Have not decoded any values from the data page yet
-      num_decoded_values_ = 0;
-
-      buffer = page->data();
-
-      // If the data page includes repetition and definition levels, we
-      // initialize the level decoder and subtract the encoded level bytes from
-      // the page size to determine the number of bytes in the encoded data.
-      int64_t data_size = page->size();
-
-      // Data page Layout: Repetition Levels - Definition Levels - encoded values.
-      // Levels are encoded as rle or bit-packed.
-      // Init repetition levels
-      if (descr_->max_repetition_level() > 0) {
-        int64_t rep_levels_bytes = repetition_level_decoder_.SetData(
-            page->repetition_level_encoding(), descr_->max_repetition_level(),
-            static_cast<int>(num_buffered_values_), buffer);
-        buffer += rep_levels_bytes;
-        data_size -= rep_levels_bytes;
-      }
-      // TODO figure a way to set max_definition_level_ to 0
-      // if the initial value is invalid
-
-      // Init definition levels
-      if (descr_->max_definition_level() > 0) {
-        int64_t def_levels_bytes = definition_level_decoder_.SetData(
-            page->definition_level_encoding(), descr_->max_definition_level(),
-            static_cast<int>(num_buffered_values_), buffer);
-        buffer += def_levels_bytes;
-        data_size -= def_levels_bytes;
-      }
-
-      // Get a decoder object for this page or create a new decoder if this is the
-      // first page with this encoding.
-      Encoding::type encoding = page->encoding();
-
-      if (IsDictionaryIndexEncoding(encoding)) {
-        encoding = Encoding::RLE_DICTIONARY;
-      }
-
-      auto it = decoders_.find(static_cast<int>(encoding));
-      if (it != decoders_.end()) {
-        if (encoding == Encoding::RLE_DICTIONARY) {
-          DCHECK(current_decoder_->encoding() == Encoding::RLE_DICTIONARY);
-        }
-        current_decoder_ = it->second.get();
-      } else {
-        switch (encoding) {
-          case Encoding::PLAIN: {
-            std::shared_ptr<DecoderType> decoder(new PlainDecoder<DType>(descr_));
-            decoders_[static_cast<int>(encoding)] = decoder;
-            current_decoder_ = decoder.get();
-            break;
-          }
-          case Encoding::RLE_DICTIONARY:
-            throw ParquetException("Dictionary page must be before data page.");
-
-          case Encoding::DELTA_BINARY_PACKED:
-          case Encoding::DELTA_LENGTH_BYTE_ARRAY:
-          case Encoding::DELTA_BYTE_ARRAY:
-            ParquetException::NYI("Unsupported encoding");
-
-          default:
-            throw ParquetException("Unknown encoding type.");
-        }
-      }
-      current_decoder_->SetData(static_cast<int>(num_buffered_values_), buffer,
-                                static_cast<int>(data_size));
-      return true;
-    } else {
-      // We don't know what this page type is. We're allowed to skip non-data
-      // pages.
-      continue;
-    }
-  }
-  return true;
-}
-
-// ----------------------------------------------------------------------
-// Batch read APIs
-
-int64_t ColumnReader::ReadDefinitionLevels(int64_t batch_size, int16_t* levels) {
-  if (descr_->max_definition_level() == 0) {
-    return 0;
-  }
-  return definition_level_decoder_.Decode(static_cast<int>(batch_size), levels);
-}
-
-int64_t ColumnReader::ReadRepetitionLevels(int64_t batch_size, int16_t* levels) {
-  if (descr_->max_repetition_level() == 0) {
-    return 0;
-  }
-  return repetition_level_decoder_.Decode(static_cast<int>(batch_size), levels);
-}
-
-// ----------------------------------------------------------------------
-// Dynamic column reader constructor
-
-std::shared_ptr<ColumnReader> ColumnReader::Make(const ColumnDescriptor* descr,
-                                                 std::unique_ptr<PageReader> pager,
-                                                 MemoryPool* pool) {
-  switch (descr->physical_type()) {
-    case Type::BOOLEAN:
-      return std::make_shared<BoolReader>(descr, std::move(pager), pool);
-    case Type::INT32:
-      return std::make_shared<Int32Reader>(descr, std::move(pager), pool);
-    case Type::INT64:
-      return std::make_shared<Int64Reader>(descr, std::move(pager), pool);
-    case Type::INT96:
-      return std::make_shared<Int96Reader>(descr, std::move(pager), pool);
-    case Type::FLOAT:
-      return std::make_shared<FloatReader>(descr, std::move(pager), pool);
-    case Type::DOUBLE:
-      return std::make_shared<DoubleReader>(descr, std::move(pager), pool);
-    case Type::BYTE_ARRAY:
-      return std::make_shared<ByteArrayReader>(descr, std::move(pager), pool);
-    case Type::FIXED_LEN_BYTE_ARRAY:
-      return std::make_shared<FixedLenByteArrayReader>(descr, std::move(pager), pool);
-    default:
-      ParquetException::NYI("type reader not implemented");
-  }
-  // Unreachable code, but supress compiler warning
-  return std::shared_ptr<ColumnReader>(nullptr);
-}
-
-// ----------------------------------------------------------------------
-// Instantiate templated classes
-
-template class PARQUET_TEMPLATE_EXPORT TypedColumnReader<BooleanType>;
-template class PARQUET_TEMPLATE_EXPORT TypedColumnReader<Int32Type>;
-template class PARQUET_TEMPLATE_EXPORT TypedColumnReader<Int64Type>;
-template class PARQUET_TEMPLATE_EXPORT TypedColumnReader<Int96Type>;
-template class PARQUET_TEMPLATE_EXPORT TypedColumnReader<FloatType>;
-template class PARQUET_TEMPLATE_EXPORT TypedColumnReader<DoubleType>;
-template class PARQUET_TEMPLATE_EXPORT TypedColumnReader<ByteArrayType>;
-template class PARQUET_TEMPLATE_EXPORT TypedColumnReader<FLBAType>;
-
-}  // namespace parquet
diff --git a/src/parquet/column_reader.h b/src/parquet/column_reader.h
deleted file mode 100644
index 7134632..0000000
--- a/src/parquet/column_reader.h
+++ /dev/null
@@ -1,535 +0,0 @@
-// 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.
-
-#ifndef PARQUET_COLUMN_READER_H
-#define PARQUET_COLUMN_READER_H
-
-#include <algorithm>
-#include <climits>
-#include <cstdint>
-#include <cstring>
-#include <iostream>
-#include <memory>
-#include <unordered_map>
-#include <vector>
-
-#include <arrow/buffer.h>
-#include <arrow/builder.h>
-#include <arrow/memory_pool.h>
-#include <arrow/util/bit-util.h>
-
-#include "parquet/column_page.h"
-#include "parquet/encoding.h"
-#include "parquet/exception.h"
-#include "parquet/schema.h"
-#include "parquet/types.h"
-#include "parquet/util/memory.h"
-#include "parquet/util/visibility.h"
-
-namespace arrow {
-
-class BitReader;
-class RleDecoder;
-
-}  // namespace arrow
-
-namespace parquet {
-
-// 16 MB is the default maximum page header size
-static constexpr uint32_t kDefaultMaxPageHeaderSize = 16 * 1024 * 1024;
-
-// 16 KB is the default expected page header size
-static constexpr uint32_t kDefaultPageHeaderSize = 16 * 1024;
-
-namespace BitUtil = ::arrow::BitUtil;
-
-class PARQUET_EXPORT LevelDecoder {
- public:
-  LevelDecoder();
-  ~LevelDecoder();
-
-  // Initialize the LevelDecoder state with new data
-  // and return the number of bytes consumed
-  int SetData(Encoding::type encoding, int16_t max_level, int num_buffered_values,
-              const uint8_t* data);
-
-  // Decodes a batch of levels into an array and returns the number of levels decoded
-  int Decode(int batch_size, int16_t* levels);
-
- private:
-  int bit_width_;
-  int num_values_remaining_;
-  Encoding::type encoding_;
-  std::unique_ptr<::arrow::RleDecoder> rle_decoder_;
-  std::unique_ptr<::arrow::BitReader> bit_packed_decoder_;
-};
-
-// Abstract page iterator interface. This way, we can feed column pages to the
-// ColumnReader through whatever mechanism we choose
-class PARQUET_EXPORT PageReader {
- public:
-  virtual ~PageReader() = default;
-
-  static std::unique_ptr<PageReader> Open(
-      std::unique_ptr<InputStream> stream, int64_t total_num_rows,
-      Compression::type codec,
-      ::arrow::MemoryPool* pool = ::arrow::default_memory_pool());
-
-  // @returns: shared_ptr<Page>(nullptr) on EOS, std::shared_ptr<Page>
-  // containing new Page otherwise
-  virtual std::shared_ptr<Page> NextPage() = 0;
-
-  virtual void set_max_page_header_size(uint32_t size) = 0;
-};
-
-class PARQUET_EXPORT ColumnReader {
- public:
-  ColumnReader(const ColumnDescriptor*, std::unique_ptr<PageReader>,
-               ::arrow::MemoryPool* pool = ::arrow::default_memory_pool());
-  virtual ~ColumnReader();
-
-  static std::shared_ptr<ColumnReader> Make(
-      const ColumnDescriptor* descr, std::unique_ptr<PageReader> pager,
-      ::arrow::MemoryPool* pool = ::arrow::default_memory_pool());
-
-  // Returns true if there are still values in this column.
-  bool HasNext() {
-    // Either there is no data page available yet, or the data page has been
-    // exhausted
-    if (num_buffered_values_ == 0 || num_decoded_values_ == num_buffered_values_) {
-      if (!ReadNewPage() || num_buffered_values_ == 0) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  Type::type type() const { return descr_->physical_type(); }
-
-  const ColumnDescriptor* descr() const { return descr_; }
-
- protected:
-  virtual bool ReadNewPage() = 0;
-
-  // Read multiple definition levels into preallocated memory
-  //
-  // Returns the number of decoded definition levels
-  int64_t ReadDefinitionLevels(int64_t batch_size, int16_t* levels);
-
-  // Read multiple repetition levels into preallocated memory
-  // Returns the number of decoded repetition levels
-  int64_t ReadRepetitionLevels(int64_t batch_size, int16_t* levels);
-
-  int64_t available_values_current_page() const {
-    return num_buffered_values_ - num_decoded_values_;
-  }
-
-  void ConsumeBufferedValues(int64_t num_values) { num_decoded_values_ += num_values; }
-
-  const ColumnDescriptor* descr_;
-
-  std::unique_ptr<PageReader> pager_;
-  std::shared_ptr<Page> current_page_;
-
-  // Not set if full schema for this field has no optional or repeated elements
-  LevelDecoder definition_level_decoder_;
-
-  // Not set for flat schemas.
-  LevelDecoder repetition_level_decoder_;
-
-  // The total number of values stored in the data page. This is the maximum of
-  // the number of encoded definition levels or encoded values. For
-  // non-repeated, required columns, this is equal to the number of encoded
-  // values. For repeated or optional values, there may be fewer data values
-  // than levels, and this tells you how many encoded levels there are in that
-  // case.
-  int64_t num_buffered_values_;
-
-  // The number of values from the current data page that have been decoded
-  // into memory
-  int64_t num_decoded_values_;
-
-  ::arrow::MemoryPool* pool_;
-};
-
-namespace internal {
-
-static inline void DefinitionLevelsToBitmap(
-    const int16_t* def_levels, int64_t num_def_levels, const int16_t max_definition_level,
-    const int16_t max_repetition_level, int64_t* values_read, int64_t* null_count,
-    uint8_t* valid_bits, const int64_t valid_bits_offset) {
-  ::arrow::internal::BitmapWriter valid_bits_writer(valid_bits, valid_bits_offset,
-                                                    num_def_levels);
-
-  // TODO(itaiin): As an interim solution we are splitting the code path here
-  // between repeated+flat column reads, and non-repeated+nested reads.
-  // Those paths need to be merged in the future
-  for (int i = 0; i < num_def_levels; ++i) {
-    if (def_levels[i] == max_definition_level) {
-      valid_bits_writer.Set();
-    } else if (max_repetition_level > 0) {
-      // repetition+flat case
-      if (def_levels[i] == (max_definition_level - 1)) {
-        valid_bits_writer.Clear();
-        *null_count += 1;
-      } else {
-        continue;
-      }
-    } else {
-      // non-repeated+nested case
-      if (def_levels[i] < max_definition_level) {
-        valid_bits_writer.Clear();
-        *null_count += 1;
-      } else {
-        throw ParquetException("definition level exceeds maximum");
-      }
-    }
-
-    valid_bits_writer.Next();
-  }
-  valid_bits_writer.Finish();
-  *values_read = valid_bits_writer.position();
-}
-
-}  // namespace internal
-
-// API to read values from a single column. This is a main client facing API.
-template <typename DType>
-class PARQUET_EXPORT TypedColumnReader : public ColumnReader {
- public:
-  typedef typename DType::c_type T;
-
-  TypedColumnReader(const ColumnDescriptor* schema, std::unique_ptr<PageReader> pager,
-                    ::arrow::MemoryPool* pool = ::arrow::default_memory_pool())
-      : ColumnReader(schema, std::move(pager), pool), current_decoder_(nullptr) {}
-
-  // Read a batch of repetition levels, definition levels, and values from the
-  // column.
-  //
-  // Since null values are not stored in the values, the number of values read
-  // may be less than the number of repetition and definition levels. With
-  // nested data this is almost certainly true.
-  //
-  // Set def_levels or rep_levels to nullptr if you want to skip reading them.
-  // This is only safe if you know through some other source that there are no
-  // undefined values.
-  //
-  // To fully exhaust a row group, you must read batches until the number of
-  // values read reaches the number of stored values according to the metadata.
-  //
-  // This API is the same for both V1 and V2 of the DataPage
-  //
-  // @returns: actual number of levels read (see values_read for number of values read)
-  int64_t ReadBatch(int64_t batch_size, int16_t* def_levels, int16_t* rep_levels,
-                    T* values, int64_t* values_read);
-
-  /// Read a batch of repetition levels, definition levels, and values from the
-  /// column and leave spaces for null entries on the lowest level in the values
-  /// buffer.
-  ///
-  /// In comparision to ReadBatch the length of repetition and definition levels
-  /// is the same as of the number of values read for max_definition_level == 1.
-  /// In the case of max_definition_level > 1, the repetition and definition
-  /// levels are larger than the values but the values include the null entries
-  /// with definition_level == (max_definition_level - 1).
-  ///
-  /// To fully exhaust a row group, you must read batches until the number of
-  /// values read reaches the number of stored values according to the metadata.
-  ///
-  /// @param batch_size the number of levels to read
-  /// @param[out] def_levels The Parquet definition levels, output has
-  ///   the length levels_read.
-  /// @param[out] rep_levels The Parquet repetition levels, output has
-  ///   the length levels_read.
-  /// @param[out] values The values in the lowest nested level including
-  ///   spacing for nulls on the lowest levels; output has the length
-  ///   values_read.
-  /// @param[out] valid_bits Memory allocated for a bitmap that indicates if
-  ///   the row is null or on the maximum definition level. For performance
-  ///   reasons the underlying buffer should be able to store 1 bit more than
-  ///   required. If this requires an additional byte, this byte is only read
-  ///   but never written to.
-  /// @param valid_bits_offset The offset in bits of the valid_bits where the
-  ///   first relevant bit resides.
-  /// @param[out] levels_read The number of repetition/definition levels that were read.
-  /// @param[out] values_read The number of values read, this includes all
-  ///   non-null entries as well as all null-entries on the lowest level
-  ///   (i.e. definition_level == max_definition_level - 1)
-  /// @param[out] null_count The number of nulls on the lowest levels.
-  ///   (i.e. (values_read - null_count) is total number of non-null entries)
-  int64_t ReadBatchSpaced(int64_t batch_size, int16_t* def_levels, int16_t* rep_levels,
-                          T* values, uint8_t* valid_bits, int64_t valid_bits_offset,
-                          int64_t* levels_read, int64_t* values_read,
-                          int64_t* null_count);
-
-  // Skip reading levels
-  // Returns the number of levels skipped
-  int64_t Skip(int64_t num_rows_to_skip);
-
- private:
-  typedef Decoder<DType> DecoderType;
-
-  // Advance to the next data page
-  bool ReadNewPage() override;
-
-  // Read up to batch_size values from the current data page into the
-  // pre-allocated memory T*
-  //
-  // @returns: the number of values read into the out buffer
-  int64_t ReadValues(int64_t batch_size, T* out);
-
-  // Read up to batch_size values from the current data page into the
-  // pre-allocated memory T*, leaving spaces for null entries according
-  // to the def_levels.
-  //
-  // @returns: the number of values read into the out buffer
-  int64_t ReadValuesSpaced(int64_t batch_size, T* out, int64_t null_count,
-                           uint8_t* valid_bits, int64_t valid_bits_offset);
-
-  // Map of encoding type to the respective decoder object. For example, a
-  // column chunk's data pages may include both dictionary-encoded and
-  // plain-encoded data.
-  std::unordered_map<int, std::shared_ptr<DecoderType>> decoders_;
-
-  void ConfigureDictionary(const DictionaryPage* page);
-
-  DecoderType* current_decoder_;
-};
-
-// ----------------------------------------------------------------------
-// Type column reader implementations
-
-template <typename DType>
-inline int64_t TypedColumnReader<DType>::ReadValues(int64_t batch_size, T* out) {
-  int64_t num_decoded = current_decoder_->Decode(out, static_cast<int>(batch_size));
-  return num_decoded;
-}
-
-template <typename DType>
-inline int64_t TypedColumnReader<DType>::ReadValuesSpaced(int64_t batch_size, T* out,
-                                                          int64_t null_count,
-                                                          uint8_t* valid_bits,
-                                                          int64_t valid_bits_offset) {
-  return current_decoder_->DecodeSpaced(out, static_cast<int>(batch_size),
-                                        static_cast<int>(null_count), valid_bits,
-                                        valid_bits_offset);
-}
-
-template <typename DType>
-inline int64_t TypedColumnReader<DType>::ReadBatch(int64_t batch_size,
-                                                   int16_t* def_levels,
-                                                   int16_t* rep_levels, T* values,
-                                                   int64_t* values_read) {
-  // HasNext invokes ReadNewPage
-  if (!HasNext()) {
-    *values_read = 0;
-    return 0;
-  }
-
-  // TODO(wesm): keep reading data pages until batch_size is reached, or the
-  // row group is finished
-  batch_size = std::min(batch_size, num_buffered_values_ - num_decoded_values_);
-
-  int64_t num_def_levels = 0;
-  int64_t num_rep_levels = 0;
-
-  int64_t values_to_read = 0;
-
-  // If the field is required and non-repeated, there are no definition levels
-  if (descr_->max_definition_level() > 0 && def_levels) {
-    num_def_levels = ReadDefinitionLevels(batch_size, def_levels);
-    // TODO(wesm): this tallying of values-to-decode can be performed with better
-    // cache-efficiency if fused with the level decoding.
-    for (int64_t i = 0; i < num_def_levels; ++i) {
-      if (def_levels[i] == descr_->max_definition_level()) {
-        ++values_to_read;
-      }
-    }
-  } else {
-    // Required field, read all values
-    values_to_read = batch_size;
-  }
-
-  // Not present for non-repeated fields
-  if (descr_->max_repetition_level() > 0 && rep_levels) {
-    num_rep_levels = ReadRepetitionLevels(batch_size, rep_levels);
-    if (def_levels && num_def_levels != num_rep_levels) {
-      throw ParquetException("Number of decoded rep / def levels did not match");
-    }
-  }
-
-  *values_read = ReadValues(values_to_read, values);
-  int64_t total_values = std::max(num_def_levels, *values_read);
-  ConsumeBufferedValues(total_values);
-
-  return total_values;
-}
-
-namespace internal {
-
-// TODO(itaiin): another code path split to merge when the general case is done
-static inline bool HasSpacedValues(const ColumnDescriptor* descr) {
-  if (descr->max_repetition_level() > 0) {
-    // repeated+flat case
-    return !descr->schema_node()->is_required();
-  } else {
-    // non-repeated+nested case
-    // Find if a node forces nulls in the lowest level along the hierarchy
-    const schema::Node* node = descr->schema_node().get();
-    while (node) {
-      if (node->is_optional()) {
-        return true;
-      }
-      node = node->parent();
-    }
-    return false;
-  }
-}
-
-}  // namespace internal
-
-template <typename DType>
-inline int64_t TypedColumnReader<DType>::ReadBatchSpaced(
-    int64_t batch_size, int16_t* def_levels, int16_t* rep_levels, T* values,
-    uint8_t* valid_bits, int64_t valid_bits_offset, int64_t* levels_read,
-    int64_t* values_read, int64_t* null_count_out) {
-  // HasNext invokes ReadNewPage
-  if (!HasNext()) {
-    *levels_read = 0;
-    *values_read = 0;
-    *null_count_out = 0;
-    return 0;
-  }
-
-  int64_t total_values;
-  // TODO(wesm): keep reading data pages until batch_size is reached, or the
-  // row group is finished
-  batch_size = std::min(batch_size, num_buffered_values_ - num_decoded_values_);
-
-  // If the field is required and non-repeated, there are no definition levels
-  if (descr_->max_definition_level() > 0) {
-    int64_t num_def_levels = ReadDefinitionLevels(batch_size, def_levels);
-
-    // Not present for non-repeated fields
-    if (descr_->max_repetition_level() > 0) {
-      int64_t num_rep_levels = ReadRepetitionLevels(batch_size, rep_levels);
-      if (num_def_levels != num_rep_levels) {
-        throw ParquetException("Number of decoded rep / def levels did not match");
-      }
-    }
-
-    const bool has_spaced_values = internal::HasSpacedValues(descr_);
-
-    int64_t null_count = 0;
-    if (!has_spaced_values) {
-      int values_to_read = 0;
-      for (int64_t i = 0; i < num_def_levels; ++i) {
-        if (def_levels[i] == descr_->max_definition_level()) {
-          ++values_to_read;
-        }
-      }
-      total_values = ReadValues(values_to_read, values);
-      for (int64_t i = 0; i < total_values; i++) {
-        ::arrow::BitUtil::SetBit(valid_bits, valid_bits_offset + i);
-      }
-      *values_read = total_values;
-    } else {
-      int16_t max_definition_level = descr_->max_definition_level();
-      int16_t max_repetition_level = descr_->max_repetition_level();
-      internal::DefinitionLevelsToBitmap(def_levels, num_def_levels, max_definition_level,
-                                         max_repetition_level, values_read, &null_count,
-                                         valid_bits, valid_bits_offset);
-      total_values = ReadValuesSpaced(*values_read, values, static_cast<int>(null_count),
-                                      valid_bits, valid_bits_offset);
-    }
-    *levels_read = num_def_levels;
-    *null_count_out = null_count;
-
-  } else {
-    // Required field, read all values
-    total_values = ReadValues(batch_size, values);
-    for (int64_t i = 0; i < total_values; i++) {
-      ::arrow::BitUtil::SetBit(valid_bits, valid_bits_offset + i);
-    }
-    *null_count_out = 0;
-    *levels_read = total_values;
-  }
-
-  ConsumeBufferedValues(*levels_read);
-  return total_values;
-}
-
-template <typename DType>
-int64_t TypedColumnReader<DType>::Skip(int64_t num_rows_to_skip) {
-  int64_t rows_to_skip = num_rows_to_skip;
-  while (HasNext() && rows_to_skip > 0) {
-    // If the number of rows to skip is more than the number of undecoded values, skip the
-    // Page.
-    if (rows_to_skip > (num_buffered_values_ - num_decoded_values_)) {
-      rows_to_skip -= num_buffered_values_ - num_decoded_values_;
-      num_decoded_values_ = num_buffered_values_;
-    } else {
-      // We need to read this Page
-      // Jump to the right offset in the Page
-      int64_t batch_size = 1024;  // ReadBatch with a smaller memory footprint
-      int64_t values_read = 0;
-
-      std::shared_ptr<ResizableBuffer> vals = AllocateBuffer(
-          this->pool_, batch_size * type_traits<DType::type_num>::value_byte_size);
-      std::shared_ptr<ResizableBuffer> def_levels =
-          AllocateBuffer(this->pool_, batch_size * sizeof(int16_t));
-
-      std::shared_ptr<ResizableBuffer> rep_levels =
-          AllocateBuffer(this->pool_, batch_size * sizeof(int16_t));
-
-      do {
-        batch_size = std::min(batch_size, rows_to_skip);
-        values_read = ReadBatch(static_cast<int>(batch_size),
-                                reinterpret_cast<int16_t*>(def_levels->mutable_data()),
-                                reinterpret_cast<int16_t*>(rep_levels->mutable_data()),
-                                reinterpret_cast<T*>(vals->mutable_data()), &values_read);
-        rows_to_skip -= values_read;
-      } while (values_read > 0 && rows_to_skip > 0);
-    }
-  }
-  return num_rows_to_skip - rows_to_skip;
-}
-
-// ----------------------------------------------------------------------
-// Template instantiations
-
-typedef TypedColumnReader<BooleanType> BoolReader;
-typedef TypedColumnReader<Int32Type> Int32Reader;
-typedef TypedColumnReader<Int64Type> Int64Reader;
-typedef TypedColumnReader<Int96Type> Int96Reader;
-typedef TypedColumnReader<FloatType> FloatReader;
-typedef TypedColumnReader<DoubleType> DoubleReader;
-typedef TypedColumnReader<ByteArrayType> ByteArrayReader;
-typedef TypedColumnReader<FLBAType> FixedLenByteArrayReader;
-
-extern template class PARQUET_EXPORT TypedColumnReader<BooleanType>;
-extern template class PARQUET_EXPORT TypedColumnReader<Int32Type>;
-extern template class PARQUET_EXPORT TypedColumnReader<Int64Type>;
-extern template class PARQUET_EXPORT TypedColumnReader<Int96Type>;
-extern template class PARQUET_EXPORT TypedColumnReader<FloatType>;
-extern template class PARQUET_EXPORT TypedColumnReader<DoubleType>;
-extern template class PARQUET_EXPORT TypedColumnReader<ByteArrayType>;
-extern template class PARQUET_EXPORT TypedColumnReader<FLBAType>;
-
-}  // namespace parquet
-
-#endif  // PARQUET_COLUMN_READER_H
diff --git a/src/parquet/column_scanner-test.cc b/src/parquet/column_scanner-test.cc
deleted file mode 100644
index d39b910..0000000
--- a/src/parquet/column_scanner-test.cc
+++ /dev/null
@@ -1,238 +0,0 @@
-// 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.
-
-#include <gtest/gtest.h>
-
-#include <algorithm>
-#include <cstdint>
-#include <cstdlib>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "parquet/column_page.h"
-#include "parquet/column_scanner.h"
-#include "parquet/schema.h"
-#include "parquet/test-specialization.h"
-#include "parquet/test-util.h"
-#include "parquet/types.h"
-#include "parquet/util/test-common.h"
-
-using std::shared_ptr;
-using std::string;
-using std::vector;
-
-namespace parquet {
-
-using schema::NodePtr;
-
-namespace test {
-
-template <>
-void InitDictValues<bool>(int num_values, int dict_per_page, vector<bool>& values,
-                          vector<uint8_t>& buffer) {
-  // No op for bool
-}
-
-template <typename Type>
-class TestFlatScanner : public ::testing::Test {
- public:
-  typedef typename Type::c_type T;
-
-  void InitScanner(const ColumnDescriptor* d) {
-    std::unique_ptr<PageReader> pager(new test::MockPageReader(pages_));
-    scanner_ = Scanner::Make(ColumnReader::Make(d, std::move(pager)));
-  }
-
-  void CheckResults(int batch_size, const ColumnDescriptor* d) {
-    TypedScanner<Type>* scanner = reinterpret_cast<TypedScanner<Type>*>(scanner_.get());
-    T val;
-    bool is_null = false;
-    int16_t def_level;
-    int16_t rep_level;
-    int j = 0;
-    scanner->SetBatchSize(batch_size);
-    for (int i = 0; i < num_levels_; i++) {
-      ASSERT_TRUE(scanner->Next(&val, &def_level, &rep_level, &is_null)) << i << j;
-      if (!is_null) {
-        ASSERT_EQ(values_[j], val) << i << "V" << j;
-        j++;
-      }
-      if (d->max_definition_level() > 0) {
-        ASSERT_EQ(def_levels_[i], def_level) << i << "D" << j;
-      }
-      if (d->max_repetition_level() > 0) {
-        ASSERT_EQ(rep_levels_[i], rep_level) << i << "R" << j;
-      }
-    }
-    ASSERT_EQ(num_values_, j);
-    ASSERT_FALSE(scanner->Next(&val, &def_level, &rep_level, &is_null));
-  }
-
-  void Clear() {
-    pages_.clear();
-    values_.clear();
-    def_levels_.clear();
-    rep_levels_.clear();
-  }
-
-  void Execute(int num_pages, int levels_per_page, int batch_size,
-               const ColumnDescriptor* d, Encoding::type encoding) {
-    num_values_ = MakePages<Type>(d, num_pages, levels_per_page, def_levels_, rep_levels_,
-                                  values_, data_buffer_, pages_, encoding);
-    num_levels_ = num_pages * levels_per_page;
-    InitScanner(d);
-    CheckResults(batch_size, d);
-    Clear();
-  }
-
-  void InitDescriptors(std::shared_ptr<ColumnDescriptor>& d1,
-                       std::shared_ptr<ColumnDescriptor>& d2,
-                       std::shared_ptr<ColumnDescriptor>& d3, int length) {
-    NodePtr type;
-    type = schema::PrimitiveNode::Make("c1", Repetition::REQUIRED, Type::type_num,
-                                       LogicalType::NONE, length);
-    d1.reset(new ColumnDescriptor(type, 0, 0));
-    type = schema::PrimitiveNode::Make("c2", Repetition::OPTIONAL, Type::type_num,
-                                       LogicalType::NONE, length);
-    d2.reset(new ColumnDescriptor(type, 4, 0));
-    type = schema::PrimitiveNode::Make("c3", Repetition::REPEATED, Type::type_num,
-                                       LogicalType::NONE, length);
-    d3.reset(new ColumnDescriptor(type, 4, 2));
-  }
-
-  void ExecuteAll(int num_pages, int num_levels, int batch_size, int type_length,
-                  Encoding::type encoding = Encoding::PLAIN) {
-    std::shared_ptr<ColumnDescriptor> d1;
-    std::shared_ptr<ColumnDescriptor> d2;
-    std::shared_ptr<ColumnDescriptor> d3;
-    InitDescriptors(d1, d2, d3, type_length);
-    // evaluate REQUIRED pages
-    Execute(num_pages, num_levels, batch_size, d1.get(), encoding);
-    // evaluate OPTIONAL pages
-    Execute(num_pages, num_levels, batch_size, d2.get(), encoding);
-    // evaluate REPEATED pages
-    Execute(num_pages, num_levels, batch_size, d3.get(), encoding);
-  }
-
- protected:
-  int num_levels_;
-  int num_values_;
-  vector<shared_ptr<Page>> pages_;
-  std::shared_ptr<Scanner> scanner_;
-  vector<T> values_;
-  vector<int16_t> def_levels_;
-  vector<int16_t> rep_levels_;
-  vector<uint8_t> data_buffer_;  // For BA and FLBA
-};
-
-static int num_levels_per_page = 100;
-static int num_pages = 20;
-static int batch_size = 32;
-
-typedef ::testing::Types<Int32Type, Int64Type, Int96Type, FloatType, DoubleType,
-                         ByteArrayType>
-    TestTypes;
-
-using TestBooleanFlatScanner = TestFlatScanner<BooleanType>;
-using TestFLBAFlatScanner = TestFlatScanner<FLBAType>;
-
-TYPED_TEST_CASE(TestFlatScanner, TestTypes);
-
-TYPED_TEST(TestFlatScanner, TestPlainScanner) {
-  ASSERT_NO_FATAL_FAILURE(
-      this->ExecuteAll(num_pages, num_levels_per_page, batch_size, 0, Encoding::PLAIN));
-}
-
-TYPED_TEST(TestFlatScanner, TestDictScanner) {
-  ASSERT_NO_FATAL_FAILURE(this->ExecuteAll(num_pages, num_levels_per_page, batch_size, 0,
-                                           Encoding::RLE_DICTIONARY));
-}
-
-TEST_F(TestBooleanFlatScanner, TestPlainScanner) {
-  ASSERT_NO_FATAL_FAILURE(
-      this->ExecuteAll(num_pages, num_levels_per_page, batch_size, 0));
-}
-
-TEST_F(TestFLBAFlatScanner, TestPlainScanner) {
-  ASSERT_NO_FATAL_FAILURE(
-      this->ExecuteAll(num_pages, num_levels_per_page, batch_size, FLBA_LENGTH));
-}
-
-TEST_F(TestFLBAFlatScanner, TestDictScanner) {
-  ASSERT_NO_FATAL_FAILURE(this->ExecuteAll(num_pages, num_levels_per_page, batch_size,
-                                           FLBA_LENGTH, Encoding::RLE_DICTIONARY));
-}
-
-TEST_F(TestFLBAFlatScanner, TestPlainDictScanner) {
-  ASSERT_NO_FATAL_FAILURE(this->ExecuteAll(num_pages, num_levels_per_page, batch_size,
-                                           FLBA_LENGTH, Encoding::PLAIN_DICTIONARY));
-}
-
-// PARQUET 502
-TEST_F(TestFLBAFlatScanner, TestSmallBatch) {
-  NodePtr type =
-      schema::PrimitiveNode::Make("c1", Repetition::REQUIRED, Type::FIXED_LEN_BYTE_ARRAY,
-                                  LogicalType::DECIMAL, FLBA_LENGTH, 10, 2);
-  const ColumnDescriptor d(type, 0, 0);
-  num_values_ = MakePages<FLBAType>(&d, 1, 100, def_levels_, rep_levels_, values_,
-                                    data_buffer_, pages_);
-  num_levels_ = 1 * 100;
-  InitScanner(&d);
-  ASSERT_NO_FATAL_FAILURE(CheckResults(1, &d));
-}
-
-TEST_F(TestFLBAFlatScanner, TestDescriptorAPI) {
-  NodePtr type =
-      schema::PrimitiveNode::Make("c1", Repetition::OPTIONAL, Type::FIXED_LEN_BYTE_ARRAY,
-                                  LogicalType::DECIMAL, FLBA_LENGTH, 10, 2);
-  const ColumnDescriptor d(type, 4, 0);
-  num_values_ = MakePages<FLBAType>(&d, 1, 100, def_levels_, rep_levels_, values_,
-                                    data_buffer_, pages_);
-  num_levels_ = 1 * 100;
-  InitScanner(&d);
-  TypedScanner<FLBAType>* scanner =
-      reinterpret_cast<TypedScanner<FLBAType>*>(scanner_.get());
-  ASSERT_EQ(10, scanner->descr()->type_precision());
-  ASSERT_EQ(2, scanner->descr()->type_scale());
-  ASSERT_EQ(FLBA_LENGTH, scanner->descr()->type_length());
-}
-
-TEST_F(TestFLBAFlatScanner, TestFLBAPrinterNext) {
-  NodePtr type =
-      schema::PrimitiveNode::Make("c1", Repetition::OPTIONAL, Type::FIXED_LEN_BYTE_ARRAY,
-                                  LogicalType::DECIMAL, FLBA_LENGTH, 10, 2);
-  const ColumnDescriptor d(type, 4, 0);
-  num_values_ = MakePages<FLBAType>(&d, 1, 100, def_levels_, rep_levels_, values_,
-                                    data_buffer_, pages_);
-  num_levels_ = 1 * 100;
-  InitScanner(&d);
-  TypedScanner<FLBAType>* scanner =
-      reinterpret_cast<TypedScanner<FLBAType>*>(scanner_.get());
-  scanner->SetBatchSize(batch_size);
-  std::stringstream ss_fail;
-  for (int i = 0; i < num_levels_; i++) {
-    std::stringstream ss;
-    scanner->PrintNext(ss, 17);
-    std::string result = ss.str();
-    ASSERT_LE(17, result.size()) << i;
-  }
-  ASSERT_THROW(scanner->PrintNext(ss_fail, 17), ParquetException);
-}
-
-}  // namespace test
-}  // namespace parquet
diff --git a/src/parquet/column_scanner.cc b/src/parquet/column_scanner.cc
deleted file mode 100644
index 51c8773..0000000
--- a/src/parquet/column_scanner.cc
+++ /dev/null
@@ -1,91 +0,0 @@
-// 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.
-
-#include "parquet/column_scanner.h"
-
-#include <cstdint>
-#include <memory>
-
-#include "parquet/column_reader.h"
-#include "parquet/util/memory.h"
-
-using arrow::MemoryPool;
-
-namespace parquet {
-
-std::shared_ptr<Scanner> Scanner::Make(std::shared_ptr<ColumnReader> col_reader,
-                                       int64_t batch_size, MemoryPool* pool) {
-  switch (col_reader->type()) {
-    case Type::BOOLEAN:
-      return std::make_shared<BoolScanner>(col_reader, batch_size, pool);
-    case Type::INT32:
-      return std::make_shared<Int32Scanner>(col_reader, batch_size, pool);
-    case Type::INT64:
-      return std::make_shared<Int64Scanner>(col_reader, batch_size, pool);
-    case Type::INT96:
-      return std::make_shared<Int96Scanner>(col_reader, batch_size, pool);
-    case Type::FLOAT:
-      return std::make_shared<FloatScanner>(col_reader, batch_size, pool);
-    case Type::DOUBLE:
-      return std::make_shared<DoubleScanner>(col_reader, batch_size, pool);
-    case Type::BYTE_ARRAY:
-      return std::make_shared<ByteArrayScanner>(col_reader, batch_size, pool);
-    case Type::FIXED_LEN_BYTE_ARRAY:
-      return std::make_shared<FixedLenByteArrayScanner>(col_reader, batch_size, pool);
-    default:
-      ParquetException::NYI("type reader not implemented");
-  }
-  // Unreachable code, but supress compiler warning
-  return std::shared_ptr<Scanner>(nullptr);
-}
-
-int64_t ScanAllValues(int32_t batch_size, int16_t* def_levels, int16_t* rep_levels,
-                      uint8_t* values, int64_t* values_buffered,
-                      parquet::ColumnReader* reader) {
-  switch (reader->type()) {
-    case parquet::Type::BOOLEAN:
-      return ScanAll<parquet::BoolReader>(batch_size, def_levels, rep_levels, values,
-                                          values_buffered, reader);
-    case parquet::Type::INT32:
-      return ScanAll<parquet::Int32Reader>(batch_size, def_levels, rep_levels, values,
-                                           values_buffered, reader);
-    case parquet::Type::INT64:
-      return ScanAll<parquet::Int64Reader>(batch_size, def_levels, rep_levels, values,
-                                           values_buffered, reader);
-    case parquet::Type::INT96:
-      return ScanAll<parquet::Int96Reader>(batch_size, def_levels, rep_levels, values,
-                                           values_buffered, reader);
-    case parquet::Type::FLOAT:
-      return ScanAll<parquet::FloatReader>(batch_size, def_levels, rep_levels, values,
-                                           values_buffered, reader);
-    case parquet::Type::DOUBLE:
-      return ScanAll<parquet::DoubleReader>(batch_size, def_levels, rep_levels, values,
-                                            values_buffered, reader);
-    case parquet::Type::BYTE_ARRAY:
-      return ScanAll<parquet::ByteArrayReader>(batch_size, def_levels, rep_levels, values,
-                                               values_buffered, reader);
-    case parquet::Type::FIXED_LEN_BYTE_ARRAY:
-      return ScanAll<parquet::FixedLenByteArrayReader>(batch_size, def_levels, rep_levels,
-                                                       values, values_buffered, reader);
-    default:
-      parquet::ParquetException::NYI("type reader not implemented");
-  }
-  // Unreachable code, but supress compiler warning
-  return 0;
-}
-
-}  // namespace parquet
diff --git a/src/parquet/column_scanner.h b/src/parquet/column_scanner.h
deleted file mode 100644
index 0a866ee..0000000
--- a/src/parquet/column_scanner.h
+++ /dev/null
@@ -1,257 +0,0 @@
-// 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.
-
-#ifndef PARQUET_COLUMN_SCANNER_H
-#define PARQUET_COLUMN_SCANNER_H
-
-#include <stdio.h>
-#include <cstdint>
-#include <memory>
-#include <ostream>
-#include <string>
-#include <vector>
-
-#include "parquet/column_reader.h"
-#include "parquet/exception.h"
-#include "parquet/schema.h"
-#include "parquet/types.h"
-#include "parquet/util/memory.h"
-#include "parquet/util/visibility.h"
-
-namespace parquet {
-
-static constexpr int64_t DEFAULT_SCANNER_BATCH_SIZE = 128;
-
-class PARQUET_EXPORT Scanner {
- public:
-  explicit Scanner(std::shared_ptr<ColumnReader> reader,
-                   int64_t batch_size = DEFAULT_SCANNER_BATCH_SIZE,
-                   ::arrow::MemoryPool* pool = ::arrow::default_memory_pool())
-      : batch_size_(batch_size),
-        level_offset_(0),
-        levels_buffered_(0),
-        value_buffer_(AllocateBuffer(pool)),
-        value_offset_(0),
-        values_buffered_(0),
-        reader_(reader) {
-    def_levels_.resize(descr()->max_definition_level() > 0 ? batch_size_ : 0);
-    rep_levels_.resize(descr()->max_repetition_level() > 0 ? batch_size_ : 0);
-  }
-
-  virtual ~Scanner() {}
-
-  static std::shared_ptr<Scanner> Make(
-      std::shared_ptr<ColumnReader> col_reader,
-      int64_t batch_size = DEFAULT_SCANNER_BATCH_SIZE,
-      ::arrow::MemoryPool* pool = ::arrow::default_memory_pool());
-
-  virtual void PrintNext(std::ostream& out, int width) = 0;
-
-  bool HasNext() { return level_offset_ < levels_buffered_ || reader_->HasNext(); }
-
-  const ColumnDescriptor* descr() const { return reader_->descr(); }
-
-  int64_t batch_size() const { return batch_size_; }
-
-  void SetBatchSize(int64_t batch_size) { batch_size_ = batch_size; }
-
- protected:
-  int64_t batch_size_;
-
-  std::vector<int16_t> def_levels_;
-  std::vector<int16_t> rep_levels_;
-  int level_offset_;
-  int levels_buffered_;
-
-  std::shared_ptr<ResizableBuffer> value_buffer_;
-  int value_offset_;
-  int64_t values_buffered_;
-
- private:
-  std::shared_ptr<ColumnReader> reader_;
-};
-
-template <typename DType>
-class PARQUET_EXPORT TypedScanner : public Scanner {
- public:
-  typedef typename DType::c_type T;
-
-  explicit TypedScanner(std::shared_ptr<ColumnReader> reader,
-                        int64_t batch_size = DEFAULT_SCANNER_BATCH_SIZE,
-                        ::arrow::MemoryPool* pool = ::arrow::default_memory_pool())
-      : Scanner(reader, batch_size, pool) {
-    typed_reader_ = static_cast<TypedColumnReader<DType>*>(reader.get());
-    int value_byte_size = type_traits<DType::type_num>::value_byte_size;
-    PARQUET_THROW_NOT_OK(value_buffer_->Resize(batch_size_ * value_byte_size));
-    values_ = reinterpret_cast<T*>(value_buffer_->mutable_data());
-  }
-
-  virtual ~TypedScanner() {}
-
-  bool NextLevels(int16_t* def_level, int16_t* rep_level) {
-    if (level_offset_ == levels_buffered_) {
-      levels_buffered_ = static_cast<int>(
-          typed_reader_->ReadBatch(static_cast<int>(batch_size_), def_levels_.data(),
-                                   rep_levels_.data(), values_, &values_buffered_));
-
-      value_offset_ = 0;
-      level_offset_ = 0;
-      if (!levels_buffered_) {
-        return false;
-      }
-    }
-    *def_level = descr()->max_definition_level() > 0 ? def_levels_[level_offset_] : 0;
-    *rep_level = descr()->max_repetition_level() > 0 ? rep_levels_[level_offset_] : 0;
-    level_offset_++;
-    return true;
-  }
-
-  bool Next(T* val, int16_t* def_level, int16_t* rep_level, bool* is_null) {
-    if (level_offset_ == levels_buffered_) {
-      if (!HasNext()) {
-        // Out of data pages
-        return false;
-      }
-    }
-
-    NextLevels(def_level, rep_level);
-    *is_null = *def_level < descr()->max_definition_level();
-
-    if (*is_null) {
-      return true;
-    }
-
-    if (value_offset_ == values_buffered_) {
-      throw ParquetException("Value was non-null, but has not been buffered");
-    }
-    *val = values_[value_offset_++];
-    return true;
-  }
-
-  // Returns true if there is a next value
-  bool NextValue(T* val, bool* is_null) {
-    if (level_offset_ == levels_buffered_) {
-      if (!HasNext()) {
-        // Out of data pages
-        return false;
-      }
-    }
-
-    // Out of values
-    int16_t def_level = -1;
-    int16_t rep_level = -1;
-    NextLevels(&def_level, &rep_level);
-    *is_null = def_level < descr()->max_definition_level();
-
-    if (*is_null) {
-      return true;
-    }
-
-    if (value_offset_ == values_buffered_) {
-      throw ParquetException("Value was non-null, but has not been buffered");
-    }
-    *val = values_[value_offset_++];
-    return true;
-  }
-
-  virtual void PrintNext(std::ostream& out, int width) {
-    T val;
-    bool is_null = false;
-    char buffer[25];
-
-    if (!NextValue(&val, &is_null)) {
-      throw ParquetException("No more values buffered");
-    }
-
-    if (is_null) {
-      std::string null_fmt = format_fwf<ByteArrayType>(width);
-      snprintf(buffer, sizeof(buffer), null_fmt.c_str(), "NULL");
-    } else {
-      FormatValue(&val, buffer, sizeof(buffer), width);
-    }
-    out << buffer;
-  }
-
- private:
-  // The ownership of this object is expressed through the reader_ variable in the base
-  TypedColumnReader<DType>* typed_reader_;
-
-  inline void FormatValue(void* val, char* buffer, int bufsize, int width);
-
-  T* values_;
-};
-
-template <typename DType>
-inline void TypedScanner<DType>::FormatValue(void* val, char* buffer, int bufsize,
-                                             int width) {
-  std::string fmt = format_fwf<DType>(width);
-  snprintf(buffer, bufsize, fmt.c_str(), *reinterpret_cast<T*>(val));
-}
-
-template <>
-inline void TypedScanner<Int96Type>::FormatValue(void* val, char* buffer, int bufsize,
-                                                 int width) {
-  std::string fmt = format_fwf<Int96Type>(width);
-  std::string result = Int96ToString(*reinterpret_cast<Int96*>(val));
-  snprintf(buffer, bufsize, fmt.c_str(), result.c_str());
-}
-
-template <>
-inline void TypedScanner<ByteArrayType>::FormatValue(void* val, char* buffer, int bufsize,
-                                                     int width) {
-  std::string fmt = format_fwf<ByteArrayType>(width);
-  std::string result = ByteArrayToString(*reinterpret_cast<ByteArray*>(val));
-  snprintf(buffer, bufsize, fmt.c_str(), result.c_str());
-}
-
-template <>
-inline void TypedScanner<FLBAType>::FormatValue(void* val, char* buffer, int bufsize,
-                                                int width) {
-  std::string fmt = format_fwf<FLBAType>(width);
-  std::string result = FixedLenByteArrayToString(
-      *reinterpret_cast<FixedLenByteArray*>(val), descr()->type_length());
-  snprintf(buffer, bufsize, fmt.c_str(), result.c_str());
-}
-
-typedef TypedScanner<BooleanType> BoolScanner;
-typedef TypedScanner<Int32Type> Int32Scanner;
-typedef TypedScanner<Int64Type> Int64Scanner;
-typedef TypedScanner<Int96Type> Int96Scanner;
-typedef TypedScanner<FloatType> FloatScanner;
-typedef TypedScanner<DoubleType> DoubleScanner;
-typedef TypedScanner<ByteArrayType> ByteArrayScanner;
-typedef TypedScanner<FLBAType> FixedLenByteArrayScanner;
-
-template <typename RType>
-int64_t ScanAll(int32_t batch_size, int16_t* def_levels, int16_t* rep_levels,
-                uint8_t* values, int64_t* values_buffered,
-                parquet::ColumnReader* reader) {
-  typedef typename RType::T Type;
-  auto typed_reader = static_cast<RType*>(reader);
-  auto vals = reinterpret_cast<Type*>(&values[0]);
-  return typed_reader->ReadBatch(batch_size, def_levels, rep_levels, vals,
-                                 values_buffered);
-}
-
-int64_t PARQUET_EXPORT ScanAllValues(int32_t batch_size, int16_t* def_levels,
-                                     int16_t* rep_levels, uint8_t* values,
-                                     int64_t* values_buffered,
-                                     parquet::ColumnReader* reader);
-
-}  // namespace parquet
-
-#endif  // PARQUET_COLUMN_SCANNER_H
diff --git a/src/parquet/column_writer-test.cc b/src/parquet/column_writer-test.cc
deleted file mode 100644
index e87d549..0000000
--- a/src/parquet/column_writer-test.cc
+++ /dev/null
@@ -1,807 +0,0 @@
-// 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.
-
-#include <gtest/gtest.h>
-
-#include "parquet/column_reader.h"
-#include "parquet/column_writer.h"
-#include "parquet/parquet_types.h"
-#include "parquet/test-specialization.h"
-#include "parquet/test-util.h"
-#include "parquet/types.h"
-#include "parquet/util/comparison.h"
-#include "parquet/util/memory.h"
-
-namespace parquet {
-
-using schema::NodePtr;
-using schema::PrimitiveNode;
-
-namespace test {
-
-// The default size used in most tests.
-const int SMALL_SIZE = 100;
-#ifdef PARQUET_VALGRIND
-// Larger size to test some corner cases, only used in some specific cases.
-const int LARGE_SIZE = 10000;
-// Very large size to test dictionary fallback.
-const int VERY_LARGE_SIZE = 40000;
-#else
-// Larger size to test some corner cases, only used in some specific cases.
-const int LARGE_SIZE = 100000;
-// Very large size to test dictionary fallback.
-const int VERY_LARGE_SIZE = 400000;
-#endif
-
-template <typename TestType>
-class TestPrimitiveWriter : public PrimitiveTypedTest<TestType> {
- public:
-  typedef typename TestType::c_type T;
-
-  void SetUp() {
-    this->SetupValuesOut(SMALL_SIZE);
-    writer_properties_ = default_writer_properties();
-    definition_levels_out_.resize(SMALL_SIZE);
-    repetition_levels_out_.resize(SMALL_SIZE);
-
-    this->SetUpSchema(Repetition::REQUIRED);
-
-    descr_ = this->schema_.Column(0);
-  }
-
-  Type::type type_num() { return TestType::type_num; }
-
-  void BuildReader(int64_t num_rows,
-                   Compression::type compression = Compression::UNCOMPRESSED) {
-    auto buffer = sink_->GetBuffer();
-    std::unique_ptr<InMemoryInputStream> source(new InMemoryInputStream(buffer));
-    std::unique_ptr<PageReader> page_reader =
-        PageReader::Open(std::move(source), num_rows, compression);
-    reader_.reset(new TypedColumnReader<TestType>(this->descr_, std::move(page_reader)));
-  }
-
-  std::shared_ptr<TypedColumnWriter<TestType>> BuildWriter(
-      int64_t output_size = SMALL_SIZE,
-      const ColumnProperties& column_properties = ColumnProperties()) {
-    sink_.reset(new InMemoryOutputStream());
-    WriterProperties::Builder wp_builder;
-    if (column_properties.encoding() == Encoding::PLAIN_DICTIONARY ||
-        column_properties.encoding() == Encoding::RLE_DICTIONARY) {
-      wp_builder.enable_dictionary();
-    } else {
-      wp_builder.disable_dictionary();
-      wp_builder.encoding(column_properties.encoding());
-    }
-    wp_builder.max_statistics_size(column_properties.max_statistics_size());
-    writer_properties_ = wp_builder.build();
-
-    metadata_ = ColumnChunkMetaDataBuilder::Make(
-        writer_properties_, this->descr_, reinterpret_cast<uint8_t*>(&thrift_metadata_));
-    std::unique_ptr<PageWriter> pager =
-        PageWriter::Open(sink_.get(), column_properties.compression(), metadata_.get());
-    std::shared_ptr<ColumnWriter> writer =
-        ColumnWriter::Make(metadata_.get(), std::move(pager), writer_properties_.get());
-    return std::static_pointer_cast<TypedColumnWriter<TestType>>(writer);
-  }
-
-  void ReadColumn(Compression::type compression = Compression::UNCOMPRESSED) {
-    BuildReader(static_cast<int64_t>(this->values_out_.size()), compression);
-    reader_->ReadBatch(static_cast<int>(this->values_out_.size()),
-                       definition_levels_out_.data(), repetition_levels_out_.data(),
-                       this->values_out_ptr_, &values_read_);
-    this->SyncValuesOut();
-  }
-
-  void ReadColumnFully(Compression::type compression = Compression::UNCOMPRESSED);
-
-  void TestRequiredWithEncoding(Encoding::type encoding) {
-    return TestRequiredWithSettings(encoding, Compression::UNCOMPRESSED, false, false);
-  }
-
-  void TestRequiredWithSettings(Encoding::type encoding, Compression::type compression,
-                                bool enable_dictionary, bool enable_statistics,
-                                int64_t num_rows = SMALL_SIZE) {
-    this->GenerateData(num_rows);
-
-    this->WriteRequiredWithSettings(encoding, compression, enable_dictionary,
-                                    enable_statistics, num_rows);
-    ASSERT_NO_FATAL_FAILURE(this->ReadAndCompare(compression, num_rows));
-
-    this->WriteRequiredWithSettingsSpaced(encoding, compression, enable_dictionary,
-                                          enable_statistics, num_rows);
-    ASSERT_NO_FATAL_FAILURE(this->ReadAndCompare(compression, num_rows));
-  }
-
-  void WriteRequiredWithSettings(Encoding::type encoding, Compression::type compression,
-                                 bool enable_dictionary, bool enable_statistics,
-                                 int64_t num_rows) {
-    ColumnProperties column_properties(encoding, compression, enable_dictionary,
-                                       enable_statistics);
-    std::shared_ptr<TypedColumnWriter<TestType>> writer =
-        this->BuildWriter(num_rows, column_properties);
-    writer->WriteBatch(this->values_.size(), nullptr, nullptr, this->values_ptr_);
-    // The behaviour should be independent from the number of Close() calls
-    writer->Close();
-    writer->Close();
-  }
-
-  void WriteRequiredWithSettingsSpaced(Encoding::type encoding,
-                                       Compression::type compression,
-                                       bool enable_dictionary, bool enable_statistics,
-                                       int64_t num_rows) {
-    std::vector<uint8_t> valid_bits(
-        BitUtil::BytesForBits(static_cast<uint32_t>(this->values_.size())) + 1, 255);
-    ColumnProperties column_properties(encoding, compression, enable_dictionary,
-                                       enable_statistics);
-    std::shared_ptr<TypedColumnWriter<TestType>> writer =
-        this->BuildWriter(num_rows, column_properties);
-    writer->WriteBatchSpaced(this->values_.size(), nullptr, nullptr, valid_bits.data(), 0,
-                             this->values_ptr_);
-    // The behaviour should be independent from the number of Close() calls
-    writer->Close();
-    writer->Close();
-  }
-
-  void ReadAndCompare(Compression::type compression, int64_t num_rows) {
-    this->SetupValuesOut(num_rows);
-    this->ReadColumnFully(compression);
-    std::shared_ptr<CompareDefault<TestType>> compare;
-    compare = std::static_pointer_cast<CompareDefault<TestType>>(
-        Comparator::Make(this->descr_));
-    for (size_t i = 0; i < this->values_.size(); i++) {
-      if ((*compare)(this->values_[i], this->values_out_[i]) ||
-          (*compare)(this->values_out_[i], this->values_[i])) {
-        std::cout << "Failed at " << i << std::endl;
-      }
-      ASSERT_FALSE((*compare)(this->values_[i], this->values_out_[i]));
-      ASSERT_FALSE((*compare)(this->values_out_[i], this->values_[i]));
-    }
-    ASSERT_EQ(this->values_, this->values_out_);
-  }
-
-  int64_t metadata_num_values() {
-    // Metadata accessor must be created lazily.
-    // This is because the ColumnChunkMetaData semantics dictate the metadata object is
-    // complete (no changes to the metadata buffer can be made after instantiation)
-    auto metadata_accessor = ColumnChunkMetaData::Make(
-        reinterpret_cast<const uint8_t*>(&thrift_metadata_), this->descr_);
-    return metadata_accessor->num_values();
-  }
-
-  bool metadata_is_stats_set() {
-    // Metadata accessor must be created lazily.
-    // This is because the ColumnChunkMetaData semantics dictate the metadata object is
-    // complete (no changes to the metadata buffer can be made after instantiation)
-    ApplicationVersion app_version(this->writer_properties_->created_by());
-    auto metadata_accessor = ColumnChunkMetaData::Make(
-        reinterpret_cast<const uint8_t*>(&thrift_metadata_), this->descr_, &app_version);
-    return metadata_accessor->is_stats_set();
-  }
-
-  std::vector<Encoding::type> metadata_encodings() {
-    // Metadata accessor must be created lazily.
-    // This is because the ColumnChunkMetaData semantics dictate the metadata object is
-    // complete (no changes to the metadata buffer can be made after instantiation)
-    auto metadata_accessor = ColumnChunkMetaData::Make(
-        reinterpret_cast<const uint8_t*>(&thrift_metadata_), this->descr_);
-    return metadata_accessor->encodings();
-  }
-
- protected:
-  int64_t values_read_;
-  // Keep the reader alive as for ByteArray the lifetime of the ByteArray
-  // content is bound to the reader.
-  std::unique_ptr<TypedColumnReader<TestType>> reader_;
-
-  std::vector<int16_t> definition_levels_out_;
-  std::vector<int16_t> repetition_levels_out_;
-
-  const ColumnDescriptor* descr_;
-
- private:
-  format::ColumnChunk thrift_metadata_;
-  std::unique_ptr<ColumnChunkMetaDataBuilder> metadata_;
-  std::unique_ptr<InMemoryOutputStream> sink_;
-  std::shared_ptr<WriterProperties> writer_properties_;
-  std::vector<std::vector<uint8_t>> data_buffer_;
-};
-
-template <typename TestType>
-void TestPrimitiveWriter<TestType>::ReadColumnFully(Compression::type compression) {
-  int64_t total_values = static_cast<int64_t>(this->values_out_.size());
-  BuildReader(total_values, compression);
-  values_read_ = 0;
-  while (values_read_ < total_values) {
-    int64_t values_read_recently = 0;
-    reader_->ReadBatch(
-        static_cast<int>(this->values_out_.size()) - static_cast<int>(values_read_),
-        definition_levels_out_.data() + values_read_,
-        repetition_levels_out_.data() + values_read_,
-        this->values_out_ptr_ + values_read_, &values_read_recently);
-    values_read_ += values_read_recently;
-  }
-  this->SyncValuesOut();
-}
-
-template <>
-void TestPrimitiveWriter<Int96Type>::ReadAndCompare(Compression::type compression,
-                                                    int64_t num_rows) {
-  this->SetupValuesOut(num_rows);
-  this->ReadColumnFully(compression);
-  std::shared_ptr<CompareDefault<Int96Type>> compare;
-  compare = std::make_shared<CompareDefaultInt96>();
-  for (size_t i = 0; i < this->values_.size(); i++) {
-    if ((*compare)(this->values_[i], this->values_out_[i]) ||
-        (*compare)(this->values_out_[i], this->values_[i])) {
-      std::cout << "Failed at " << i << std::endl;
-    }
-    ASSERT_FALSE((*compare)(this->values_[i], this->values_out_[i]));
-    ASSERT_FALSE((*compare)(this->values_out_[i], this->values_[i]));
-  }
-  ASSERT_EQ(this->values_, this->values_out_);
-}
-
-template <>
-void TestPrimitiveWriter<FLBAType>::ReadColumnFully(Compression::type compression) {
-  int64_t total_values = static_cast<int64_t>(this->values_out_.size());
-  BuildReader(total_values, compression);
-  this->data_buffer_.clear();
-
-  values_read_ = 0;
-  while (values_read_ < total_values) {
-    int64_t values_read_recently = 0;
-    reader_->ReadBatch(
-        static_cast<int>(this->values_out_.size()) - static_cast<int>(values_read_),
-        definition_levels_out_.data() + values_read_,
-        repetition_levels_out_.data() + values_read_,
-        this->values_out_ptr_ + values_read_, &values_read_recently);
-
-    // Copy contents of the pointers
-    std::vector<uint8_t> data(values_read_recently * this->descr_->type_length());
-    uint8_t* data_ptr = data.data();
-    for (int64_t i = 0; i < values_read_recently; i++) {
-      memcpy(data_ptr + this->descr_->type_length() * i,
-             this->values_out_[i + values_read_].ptr, this->descr_->type_length());
-      this->values_out_[i + values_read_].ptr =
-          data_ptr + this->descr_->type_length() * i;
-    }
-    data_buffer_.emplace_back(std::move(data));
-
-    values_read_ += values_read_recently;
-  }
-  this->SyncValuesOut();
-}
-
-typedef ::testing::Types<Int32Type, Int64Type, Int96Type, FloatType, DoubleType,
-                         BooleanType, ByteArrayType, FLBAType>
-    TestTypes;
-
-TYPED_TEST_CASE(TestPrimitiveWriter, TestTypes);
-
-using TestNullValuesWriter = TestPrimitiveWriter<Int32Type>;
-
-TYPED_TEST(TestPrimitiveWriter, RequiredPlain) {
-  this->TestRequiredWithEncoding(Encoding::PLAIN);
-}
-
-TYPED_TEST(TestPrimitiveWriter, RequiredDictionary) {
-  this->TestRequiredWithEncoding(Encoding::PLAIN_DICTIONARY);
-}
-
-/*
-TYPED_TEST(TestPrimitiveWriter, RequiredRLE) {
-  this->TestRequiredWithEncoding(Encoding::RLE);
-}
-
-TYPED_TEST(TestPrimitiveWriter, RequiredBitPacked) {
-  this->TestRequiredWithEncoding(Encoding::BIT_PACKED);
-}
-
-TYPED_TEST(TestPrimitiveWriter, RequiredDeltaBinaryPacked) {
-  this->TestRequiredWithEncoding(Encoding::DELTA_BINARY_PACKED);
-}
-
-TYPED_TEST(TestPrimitiveWriter, RequiredDeltaLengthByteArray) {
-  this->TestRequiredWithEncoding(Encoding::DELTA_LENGTH_BYTE_ARRAY);
-}
-
-TYPED_TEST(TestPrimitiveWriter, RequiredDeltaByteArray) {
-  this->TestRequiredWithEncoding(Encoding::DELTA_BYTE_ARRAY);
-}
-
-TYPED_TEST(TestPrimitiveWriter, RequiredRLEDictionary) {
-  this->TestRequiredWithEncoding(Encoding::RLE_DICTIONARY);
-}
-*/
-
-TYPED_TEST(TestPrimitiveWriter, RequiredPlainWithSnappyCompression) {
-  this->TestRequiredWithSettings(Encoding::PLAIN, Compression::SNAPPY, false, false,
-                                 LARGE_SIZE);
-}
-
-TYPED_TEST(TestPrimitiveWriter, RequiredPlainWithBrotliCompression) {
-  this->TestRequiredWithSettings(Encoding::PLAIN, Compression::BROTLI, false, false,
-                                 LARGE_SIZE);
-}
-
-TYPED_TEST(TestPrimitiveWriter, RequiredPlainWithGzipCompression) {
-  this->TestRequiredWithSettings(Encoding::PLAIN, Compression::GZIP, false, false,
-                                 LARGE_SIZE);
-}
-
-TYPED_TEST(TestPrimitiveWriter, RequiredPlainWithLz4Compression) {
-  this->TestRequiredWithSettings(Encoding::PLAIN, Compression::LZ4, false, false,
-                                 LARGE_SIZE);
-}
-
-TYPED_TEST(TestPrimitiveWriter, RequiredPlainWithZstdCompression) {
-  this->TestRequiredWithSettings(Encoding::PLAIN, Compression::ZSTD, false, false,
-                                 LARGE_SIZE);
-}
-
-TYPED_TEST(TestPrimitiveWriter, RequiredPlainWithStats) {
-  this->TestRequiredWithSettings(Encoding::PLAIN, Compression::UNCOMPRESSED, false, true,
-                                 LARGE_SIZE);
-}
-
-TYPED_TEST(TestPrimitiveWriter, RequiredPlainWithStatsAndSnappyCompression) {
-  this->TestRequiredWithSettings(Encoding::PLAIN, Compression::SNAPPY, false, true,
-                                 LARGE_SIZE);
-}
-
-TYPED_TEST(TestPrimitiveWriter, RequiredPlainWithStatsAndBrotliCompression) {
-  this->TestRequiredWithSettings(Encoding::PLAIN, Compression::BROTLI, false, true,
-                                 LARGE_SIZE);
-}
-
-TYPED_TEST(TestPrimitiveWriter, RequiredPlainWithStatsAndGzipCompression) {
-  this->TestRequiredWithSettings(Encoding::PLAIN, Compression::GZIP, false, true,
-                                 LARGE_SIZE);
-}
-
-TYPED_TEST(TestPrimitiveWriter, RequiredPlainWithStatsAndLz4Compression) {
-  this->TestRequiredWithSettings(Encoding::PLAIN, Compression::LZ4, false, true,
-                                 LARGE_SIZE);
-}
-
-TYPED_TEST(TestPrimitiveWriter, RequiredPlainWithStatsAndZstdCompression) {
-  this->TestRequiredWithSettings(Encoding::PLAIN, Compression::ZSTD, false, true,
-                                 LARGE_SIZE);
-}
-
-TYPED_TEST(TestPrimitiveWriter, Optional) {
-  // Optional and non-repeated, with definition levels
-  // but no repetition levels
-  this->SetUpSchema(Repetition::OPTIONAL);
-
-  this->GenerateData(SMALL_SIZE);
-  std::vector<int16_t> definition_levels(SMALL_SIZE, 1);
-  definition_levels[1] = 0;
-
-  auto writer = this->BuildWriter();
-  writer->WriteBatch(this->values_.size(), definition_levels.data(), nullptr,
-                     this->values_ptr_);
-  writer->Close();
-
-  // PARQUET-703
-  ASSERT_EQ(100, this->metadata_num_values());
-
-  this->ReadColumn();
-  ASSERT_EQ(99, this->values_read_);
-  this->values_out_.resize(99);
-  this->values_.resize(99);
-  ASSERT_EQ(this->values_, this->values_out_);
-}
-
-TYPED_TEST(TestPrimitiveWriter, OptionalSpaced) {
-  // Optional and non-repeated, with definition levels
-  // but no repetition levels
-  this->SetUpSchema(Repetition::OPTIONAL);
-
-  this->GenerateData(SMALL_SIZE);
-  std::vector<int16_t> definition_levels(SMALL_SIZE, 1);
-  std::vector<uint8_t> valid_bits(::arrow::BitUtil::BytesForBits(SMALL_SIZE), 255);
-
-  definition_levels[SMALL_SIZE - 1] = 0;
-  ::arrow::BitUtil::ClearBit(valid_bits.data(), SMALL_SIZE - 1);
-  definition_levels[1] = 0;
-  ::arrow::BitUtil::ClearBit(valid_bits.data(), 1);
-
-  auto writer = this->BuildWriter();
-  writer->WriteBatchSpaced(this->values_.size(), definition_levels.data(), nullptr,
-                           valid_bits.data(), 0, this->values_ptr_);
-  writer->Close();
-
-  // PARQUET-703
-  ASSERT_EQ(100, this->metadata_num_values());
-
-  this->ReadColumn();
-  ASSERT_EQ(98, this->values_read_);
-  this->values_out_.resize(98);
-  this->values_.resize(99);
-  this->values_.erase(this->values_.begin() + 1);
-  ASSERT_EQ(this->values_, this->values_out_);
-}
-
-TYPED_TEST(TestPrimitiveWriter, Repeated) {
-  // Optional and repeated, so definition and repetition levels
-  this->SetUpSchema(Repetition::REPEATED);
-
-  this->GenerateData(SMALL_SIZE);
-  std::vector<int16_t> definition_levels(SMALL_SIZE, 1);
-  definition_levels[1] = 0;
-  std::vector<int16_t> repetition_levels(SMALL_SIZE, 0);
-
-  auto writer = this->BuildWriter();
-  writer->WriteBatch(this->values_.size(), definition_levels.data(),
-                     repetition_levels.data(), this->values_ptr_);
-  writer->Close();
-
-  this->ReadColumn();
-  ASSERT_EQ(SMALL_SIZE - 1, this->values_read_);
-  this->values_out_.resize(SMALL_SIZE - 1);
-  this->values_.resize(SMALL_SIZE - 1);
-  ASSERT_EQ(this->values_, this->values_out_);
-}
-
-TYPED_TEST(TestPrimitiveWriter, RequiredLargeChunk) {
-  this->GenerateData(LARGE_SIZE);
-
-  // Test case 1: required and non-repeated, so no definition or repetition levels
-  auto writer = this->BuildWriter(LARGE_SIZE);
-  writer->WriteBatch(this->values_.size(), nullptr, nullptr, this->values_ptr_);
-  writer->Close();
-
-  // Just read the first SMALL_SIZE rows to ensure we could read it back in
-  this->ReadColumn();
-  ASSERT_EQ(SMALL_SIZE, this->values_read_);
-  this->values_.resize(SMALL_SIZE);
-  ASSERT_EQ(this->values_, this->values_out_);
-}
-
-// Test case for dictionary fallback encoding
-TYPED_TEST(TestPrimitiveWriter, RequiredVeryLargeChunk) {
-  this->GenerateData(VERY_LARGE_SIZE);
-
-  auto writer = this->BuildWriter(VERY_LARGE_SIZE, Encoding::PLAIN_DICTIONARY);
-  writer->WriteBatch(this->values_.size(), nullptr, nullptr, this->values_ptr_);
-  writer->Close();
-
-  // Read all rows so we are sure that also the non-dictionary pages are read correctly
-  this->SetupValuesOut(VERY_LARGE_SIZE);
-  this->ReadColumnFully();
-  ASSERT_EQ(VERY_LARGE_SIZE, this->values_read_);
-  this->values_.resize(VERY_LARGE_SIZE);
-  ASSERT_EQ(this->values_, this->values_out_);
-  std::vector<Encoding::type> encodings = this->metadata_encodings();
-  // There are 3 encodings (RLE, PLAIN_DICTIONARY, PLAIN) in a fallback case
-  // Dictionary encoding is not allowed for boolean type
-  // There are 2 encodings (RLE, PLAIN) in a non dictionary encoding case
-  if (this->type_num() != Type::BOOLEAN) {
-    ASSERT_EQ(Encoding::PLAIN_DICTIONARY, encodings[0]);
-    ASSERT_EQ(Encoding::PLAIN, encodings[1]);
-    ASSERT_EQ(Encoding::RLE, encodings[2]);
-  } else {
-    ASSERT_EQ(Encoding::PLAIN, encodings[0]);
-    ASSERT_EQ(Encoding::RLE, encodings[1]);
-  }
-}
-
-// PARQUET-719
-// Test case for NULL values
-TEST_F(TestNullValuesWriter, OptionalNullValueChunk) {
-  this->SetUpSchema(Repetition::OPTIONAL);
-
-  this->GenerateData(LARGE_SIZE);
-
-  std::vector<int16_t> definition_levels(LARGE_SIZE, 0);
-  std::vector<int16_t> repetition_levels(LARGE_SIZE, 0);
-
-  auto writer = this->BuildWriter(LARGE_SIZE);
-  // All values being written are NULL
-  writer->WriteBatch(this->values_.size(), definition_levels.data(),
-                     repetition_levels.data(), nullptr);
-  writer->Close();
-
-  // Just read the first SMALL_SIZE rows to ensure we could read it back in
-  this->ReadColumn();
-  ASSERT_EQ(0, this->values_read_);
-}
-
-// PARQUET-764
-// Correct bitpacking for boolean write at non-byte boundaries
-using TestBooleanValuesWriter = TestPrimitiveWriter<BooleanType>;
-TEST_F(TestBooleanValuesWriter, AlternateBooleanValues) {
-  this->SetUpSchema(Repetition::REQUIRED);
-  auto writer = this->BuildWriter();
-  for (int i = 0; i < SMALL_SIZE; i++) {
-    bool value = (i % 2 == 0) ? true : false;
-    writer->WriteBatch(1, nullptr, nullptr, &value);
-  }
-  writer->Close();
-  this->ReadColumn();
-  for (int i = 0; i < SMALL_SIZE; i++) {
-    ASSERT_EQ((i % 2 == 0) ? true : false, this->values_out_[i]) << i;
-  }
-}
-
-// PARQUET-979
-// Prevent writing large stats
-using TestByteArrayValuesWriter = TestPrimitiveWriter<ByteArrayType>;
-TEST_F(TestByteArrayValuesWriter, OmitStats) {
-  int min_len = 1024 * 4;
-  int max_len = 1024 * 8;
-  this->SetUpSchema(Repetition::REQUIRED);
-  auto writer = this->BuildWriter();
-
-  values_.resize(SMALL_SIZE);
-  InitWideByteArrayValues(SMALL_SIZE, this->values_, this->buffer_, min_len, max_len);
-  writer->WriteBatch(SMALL_SIZE, nullptr, nullptr, this->values_.data());
-  writer->Close();
-
-  ASSERT_FALSE(this->metadata_is_stats_set());
-}
-
-TEST_F(TestByteArrayValuesWriter, LimitStats) {
-  int min_len = 1024 * 4;
-  int max_len = 1024 * 8;
-  this->SetUpSchema(Repetition::REQUIRED);
-  ColumnProperties column_properties;
-  column_properties.set_max_statistics_size(static_cast<size_t>(max_len));
-  auto writer = this->BuildWriter(SMALL_SIZE, column_properties);
-
-  values_.resize(SMALL_SIZE);
-  InitWideByteArrayValues(SMALL_SIZE, this->values_, this->buffer_, min_len, max_len);
-  writer->WriteBatch(SMALL_SIZE, nullptr, nullptr, this->values_.data());
-  writer->Close();
-
-  ASSERT_TRUE(this->metadata_is_stats_set());
-}
-
-TEST_F(TestByteArrayValuesWriter, CheckDefaultStats) {
-  this->SetUpSchema(Repetition::REQUIRED);
-  auto writer = this->BuildWriter();
-  this->GenerateData(SMALL_SIZE);
-
-  writer->WriteBatch(SMALL_SIZE, nullptr, nullptr, this->values_ptr_);
-  writer->Close();
-
-  ASSERT_TRUE(this->metadata_is_stats_set());
-}
-
-void GenerateLevels(int min_repeat_factor, int max_repeat_factor, int max_level,
-                    std::vector<int16_t>& input_levels) {
-  // for each repetition count upto max_repeat_factor
-  for (int repeat = min_repeat_factor; repeat <= max_repeat_factor; repeat++) {
-    // repeat count increases by a factor of 2 for every iteration
-    int repeat_count = (1 << repeat);
-    // generate levels for repetition count upto the maximum level
-    int16_t value = 0;
-    int bwidth = 0;
-    while (value <= max_level) {
-      for (int i = 0; i < repeat_count; i++) {
-        input_levels.push_back(value);
-      }
-      value = static_cast<int16_t>((2 << bwidth) - 1);
-      bwidth++;
-    }
-  }
-}
-
-void EncodeLevels(Encoding::type encoding, int16_t max_level, int num_levels,
-                  const int16_t* input_levels, std::vector<uint8_t>& bytes) {
-  LevelEncoder encoder;
-  int levels_count = 0;
-  bytes.resize(2 * num_levels);
-  ASSERT_EQ(2 * num_levels, static_cast<int>(bytes.size()));
-  // encode levels
-  if (encoding == Encoding::RLE) {
-    // leave space to write the rle length value
-    encoder.Init(encoding, max_level, num_levels, bytes.data() + sizeof(int32_t),
-                 static_cast<int>(bytes.size()));
-
-    levels_count = encoder.Encode(num_levels, input_levels);
-    (reinterpret_cast<int32_t*>(bytes.data()))[0] = encoder.len();
-  } else {
-    encoder.Init(encoding, max_level, num_levels, bytes.data(),
-                 static_cast<int>(bytes.size()));
-    levels_count = encoder.Encode(num_levels, input_levels);
-  }
-  ASSERT_EQ(num_levels, levels_count);
-}
-
-void VerifyDecodingLevels(Encoding::type encoding, int16_t max_level,
-                          std::vector<int16_t>& input_levels,
-                          std::vector<uint8_t>& bytes) {
-  LevelDecoder decoder;
-  int levels_count = 0;
-  std::vector<int16_t> output_levels;
-  int num_levels = static_cast<int>(input_levels.size());
-
-  output_levels.resize(num_levels);
-  ASSERT_EQ(num_levels, static_cast<int>(output_levels.size()));
-
-  // Decode levels and test with multiple decode calls
-  decoder.SetData(encoding, max_level, num_levels, bytes.data());
-  int decode_count = 4;
-  int num_inner_levels = num_levels / decode_count;
-  // Try multiple decoding on a single SetData call
-  for (int ct = 0; ct < decode_count; ct++) {
-    int offset = ct * num_inner_levels;
-    levels_count = decoder.Decode(num_inner_levels, output_levels.data());
-    ASSERT_EQ(num_inner_levels, levels_count);
-    for (int i = 0; i < num_inner_levels; i++) {
-      EXPECT_EQ(input_levels[i + offset], output_levels[i]);
-    }
-  }
-  // check the remaining levels
-  int num_levels_completed = decode_count * (num_levels / decode_count);
-  int num_remaining_levels = num_levels - num_levels_completed;
-  if (num_remaining_levels > 0) {
-    levels_count = decoder.Decode(num_remaining_levels, output_levels.data());
-    ASSERT_EQ(num_remaining_levels, levels_count);
-    for (int i = 0; i < num_remaining_levels; i++) {
-      EXPECT_EQ(input_levels[i + num_levels_completed], output_levels[i]);
-    }
-  }
-  // Test zero Decode values
-  ASSERT_EQ(0, decoder.Decode(1, output_levels.data()));
-}
-
-void VerifyDecodingMultipleSetData(Encoding::type encoding, int16_t max_level,
-                                   std::vector<int16_t>& input_levels,
-                                   std::vector<std::vector<uint8_t>>& bytes) {
-  LevelDecoder decoder;
-  int levels_count = 0;
-  std::vector<int16_t> output_levels;
-
-  // Decode levels and test with multiple SetData calls
-  int setdata_count = static_cast<int>(bytes.size());
-  int num_levels = static_cast<int>(input_levels.size()) / setdata_count;
-  output_levels.resize(num_levels);
-  // Try multiple SetData
-  for (int ct = 0; ct < setdata_count; ct++) {
-    int offset = ct * num_levels;
-    ASSERT_EQ(num_levels, static_cast<int>(output_levels.size()));
-    decoder.SetData(encoding, max_level, num_levels, bytes[ct].data());
-    levels_count = decoder.Decode(num_levels, output_levels.data());
-    ASSERT_EQ(num_levels, levels_count);
-    for (int i = 0; i < num_levels; i++) {
-      EXPECT_EQ(input_levels[i + offset], output_levels[i]);
-    }
-  }
-}
-
-// Test levels with maximum bit-width from 1 to 8
-// increase the repetition count for each iteration by a factor of 2
-TEST(TestLevels, TestLevelsDecodeMultipleBitWidth) {
-  int min_repeat_factor = 0;
-  int max_repeat_factor = 7;  // 128
-  int max_bit_width = 8;
-  std::vector<int16_t> input_levels;
-  std::vector<uint8_t> bytes;
-  Encoding::type encodings[2] = {Encoding::RLE, Encoding::BIT_PACKED};
-
-  // for each encoding
-  for (int encode = 0; encode < 2; encode++) {
-    Encoding::type encoding = encodings[encode];
-    // BIT_PACKED requires a sequence of atleast 8
-    if (encoding == Encoding::BIT_PACKED) min_repeat_factor = 3;
-    // for each maximum bit-width
-    for (int bit_width = 1; bit_width <= max_bit_width; bit_width++) {
-      // find the maximum level for the current bit_width
-      int16_t max_level = static_cast<int16_t>((1 << bit_width) - 1);
-      // Generate levels
-      GenerateLevels(min_repeat_factor, max_repeat_factor, max_level, input_levels);
-      ASSERT_NO_FATAL_FAILURE(EncodeLevels(encoding, max_level,
-                                           static_cast<int>(input_levels.size()),
-                                           input_levels.data(), bytes));
-      ASSERT_NO_FATAL_FAILURE(
-          VerifyDecodingLevels(encoding, max_level, input_levels, bytes));
-      input_levels.clear();
-    }
-  }
-}
-
-// Test multiple decoder SetData calls
-TEST(TestLevels, TestLevelsDecodeMultipleSetData) {
-  int min_repeat_factor = 3;
-  int max_repeat_factor = 7;  // 128
-  int bit_width = 8;
-  int16_t max_level = static_cast<int16_t>((1 << bit_width) - 1);
-  std::vector<int16_t> input_levels;
-  std::vector<std::vector<uint8_t>> bytes;
-  Encoding::type encodings[2] = {Encoding::RLE, Encoding::BIT_PACKED};
-  GenerateLevels(min_repeat_factor, max_repeat_factor, max_level, input_levels);
-  int num_levels = static_cast<int>(input_levels.size());
-  int setdata_factor = 8;
-  int split_level_size = num_levels / setdata_factor;
-  bytes.resize(setdata_factor);
-
-  // for each encoding
-  for (int encode = 0; encode < 2; encode++) {
-    Encoding::type encoding = encodings[encode];
-    for (int rf = 0; rf < setdata_factor; rf++) {
-      int offset = rf * split_level_size;
-      ASSERT_NO_FATAL_FAILURE(EncodeLevels(
-          encoding, max_level, split_level_size,
-          reinterpret_cast<int16_t*>(input_levels.data()) + offset, bytes[rf]));
-    }
-    ASSERT_NO_FATAL_FAILURE(
-        VerifyDecodingMultipleSetData(encoding, max_level, input_levels, bytes));
-  }
-}
-
-TEST(TestLevelEncoder, MinimumBufferSize) {
-  // PARQUET-676, PARQUET-698
-  const int kNumToEncode = 1024;
-
-  std::vector<int16_t> levels;
-  for (int i = 0; i < kNumToEncode; ++i) {
-    if (i % 9 == 0) {
-      levels.push_back(0);
-    } else {
-      levels.push_back(1);
-    }
-  }
-
-  std::vector<uint8_t> output(
-      LevelEncoder::MaxBufferSize(Encoding::RLE, 1, kNumToEncode));
-
-  LevelEncoder encoder;
-  encoder.Init(Encoding::RLE, 1, kNumToEncode, output.data(),
-               static_cast<int>(output.size()));
-  int encode_count = encoder.Encode(kNumToEncode, levels.data());
-
-  ASSERT_EQ(kNumToEncode, encode_count);
-}
-
-TEST(TestLevelEncoder, MinimumBufferSize2) {
-  // PARQUET-708
-  // Test the worst case for bit_width=2 consisting of
-  // LiteralRun(size=8)
-  // RepeatedRun(size=8)
-  // LiteralRun(size=8)
-  // ...
-  const int kNumToEncode = 1024;
-
-  std::vector<int16_t> levels;
-  for (int i = 0; i < kNumToEncode; ++i) {
-    // This forces a literal run of 00000001
-    // followed by eight 1s
-    if ((i % 16) < 7) {
-      levels.push_back(0);
-    } else {
-      levels.push_back(1);
-    }
-  }
-
-  for (int16_t bit_width = 1; bit_width <= 8; bit_width++) {
-    std::vector<uint8_t> output(
-        LevelEncoder::MaxBufferSize(Encoding::RLE, bit_width, kNumToEncode));
-
-    LevelEncoder encoder;
-    encoder.Init(Encoding::RLE, bit_width, kNumToEncode, output.data(),
-                 static_cast<int>(output.size()));
-    int encode_count = encoder.Encode(kNumToEncode, levels.data());
-
-    ASSERT_EQ(kNumToEncode, encode_count);
-  }
-}
-
-}  // namespace test
-}  // namespace parquet
diff --git a/src/parquet/column_writer.cc b/src/parquet/column_writer.cc
deleted file mode 100644
index a65bda8..0000000
--- a/src/parquet/column_writer.cc
+++ /dev/null
@@ -1,867 +0,0 @@
-// 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.
-
-#include "parquet/column_writer.h"
-
-#include <cstdint>
-#include <memory>
-
-#include "arrow/util/bit-util.h"
-#include "arrow/util/compression.h"
-#include "arrow/util/rle-encoding.h"
-
-#include "parquet/encoding-internal.h"
-#include "parquet/properties.h"
-#include "parquet/statistics.h"
-#include "parquet/thrift.h"
-#include "parquet/util/logging.h"
-#include "parquet/util/memory.h"
-
-namespace parquet {
-
-using BitWriter = ::arrow::BitWriter;
-using RleEncoder = ::arrow::RleEncoder;
-
-LevelEncoder::LevelEncoder() {}
-LevelEncoder::~LevelEncoder() {}
-
-void LevelEncoder::Init(Encoding::type encoding, int16_t max_level,
-                        int num_buffered_values, uint8_t* data, int data_size) {
-  bit_width_ = BitUtil::Log2(max_level + 1);
-  encoding_ = encoding;
-  switch (encoding) {
-    case Encoding::RLE: {
-      rle_encoder_.reset(new RleEncoder(data, data_size, bit_width_));
-      break;
-    }
-    case Encoding::BIT_PACKED: {
-      int num_bytes =
-          static_cast<int>(BitUtil::BytesForBits(num_buffered_values * bit_width_));
-      bit_packed_encoder_.reset(new BitWriter(data, num_bytes));
-      break;
-    }
-    default:
-      throw ParquetException("Unknown encoding type for levels.");
-  }
-}
-
-int LevelEncoder::MaxBufferSize(Encoding::type encoding, int16_t max_level,
-                                int num_buffered_values) {
-  int bit_width = BitUtil::Log2(max_level + 1);
-  int num_bytes = 0;
-  switch (encoding) {
-    case Encoding::RLE: {
-      // TODO: Due to the way we currently check if the buffer is full enough,
-      // we need to have MinBufferSize as head room.
-      num_bytes = RleEncoder::MaxBufferSize(bit_width, num_buffered_values) +
-                  RleEncoder::MinBufferSize(bit_width);
-      break;
-    }
-    case Encoding::BIT_PACKED: {
-      num_bytes =
-          static_cast<int>(BitUtil::BytesForBits(num_buffered_values * bit_width));
-      break;
-    }
-    default:
-      throw ParquetException("Unknown encoding type for levels.");
-  }
-  return num_bytes;
-}
-
-int LevelEncoder::Encode(int batch_size, const int16_t* levels) {
-  int num_encoded = 0;
-  if (!rle_encoder_ && !bit_packed_encoder_) {
-    throw ParquetException("Level encoders are not initialized.");
-  }
-
-  if (encoding_ == Encoding::RLE) {
-    for (int i = 0; i < batch_size; ++i) {
-      if (!rle_encoder_->Put(*(levels + i))) {
-        break;
-      }
-      ++num_encoded;
-    }
-    rle_encoder_->Flush();
-    rle_length_ = rle_encoder_->len();
-  } else {
-    for (int i = 0; i < batch_size; ++i) {
-      if (!bit_packed_encoder_->PutValue(*(levels + i), bit_width_)) {
-        break;
-      }
-      ++num_encoded;
-    }
-    bit_packed_encoder_->Flush();
-  }
-  return num_encoded;
-}
-
-// ----------------------------------------------------------------------
-// PageWriter implementation
-
-static format::Statistics ToThrift(const EncodedStatistics& row_group_statistics) {
-  format::Statistics statistics;
-  if (row_group_statistics.has_min) statistics.__set_min(row_group_statistics.min());
-  if (row_group_statistics.has_max) statistics.__set_max(row_group_statistics.max());
-  if (row_group_statistics.has_null_count)
-    statistics.__set_null_count(row_group_statistics.null_count);
-  if (row_group_statistics.has_distinct_count)
-    statistics.__set_distinct_count(row_group_statistics.distinct_count);
-  return statistics;
-}
-
-// This subclass delimits pages appearing in a serialized stream, each preceded
-// by a serialized Thrift format::PageHeader indicating the type of each page
-// and the page metadata.
-class SerializedPageWriter : public PageWriter {
- public:
-  SerializedPageWriter(OutputStream* sink, Compression::type codec,
-                       ColumnChunkMetaDataBuilder* metadata,
-                       ::arrow::MemoryPool* pool = ::arrow::default_memory_pool())
-      : sink_(sink),
-        metadata_(metadata),
-        pool_(pool),
-        num_values_(0),
-        dictionary_page_offset_(0),
-        data_page_offset_(0),
-        total_uncompressed_size_(0),
-        total_compressed_size_(0) {
-    compressor_ = GetCodecFromArrow(codec);
-  }
-
-  int64_t WriteDictionaryPage(const DictionaryPage& page) override {
-    int64_t uncompressed_size = page.size();
-    std::shared_ptr<Buffer> compressed_data = nullptr;
-    if (has_compressor()) {
-      auto buffer = std::static_pointer_cast<ResizableBuffer>(
-          AllocateBuffer(pool_, uncompressed_size));
-      Compress(*(page.buffer().get()), buffer.get());
-      compressed_data = std::static_pointer_cast<Buffer>(buffer);
-    } else {
-      compressed_data = page.buffer();
-    }
-
-    format::DictionaryPageHeader dict_page_header;
-    dict_page_header.__set_num_values(page.num_values());
-    dict_page_header.__set_encoding(ToThrift(page.encoding()));
-    dict_page_header.__set_is_sorted(page.is_sorted());
-
-    format::PageHeader page_header;
-    page_header.__set_type(format::PageType::DICTIONARY_PAGE);
-    page_header.__set_uncompressed_page_size(static_cast<int32_t>(uncompressed_size));
-    page_header.__set_compressed_page_size(static_cast<int32_t>(compressed_data->size()));
-    page_header.__set_dictionary_page_header(dict_page_header);
-    // TODO(PARQUET-594) crc checksum
-
-    int64_t start_pos = sink_->Tell();
-    if (dictionary_page_offset_ == 0) {
-      dictionary_page_offset_ = start_pos;
-    }
-    int64_t header_size =
-        SerializeThriftMsg(&page_header, sizeof(format::PageHeader), sink_);
-    sink_->Write(compressed_data->data(), compressed_data->size());
-
-    total_uncompressed_size_ += uncompressed_size + header_size;
-    total_compressed_size_ += compressed_data->size() + header_size;
-
-    return sink_->Tell() - start_pos;
-  }
-
-  void Close(bool has_dictionary, bool fallback) override {
-    // index_page_offset = -1 since they are not supported
-    metadata_->Finish(num_values_, dictionary_page_offset_, -1, data_page_offset_,
-                      total_compressed_size_, total_uncompressed_size_, has_dictionary,
-                      fallback);
-
-    // Write metadata at end of column chunk
-    metadata_->WriteTo(sink_);
-  }
-
-  /**
-   * Compress a buffer.
-   */
-  void Compress(const Buffer& src_buffer, ResizableBuffer* dest_buffer) override {
-    DCHECK(compressor_ != nullptr);
-
-    // Compress the data
-    int64_t max_compressed_size =
-        compressor_->MaxCompressedLen(src_buffer.size(), src_buffer.data());
-
-    // Use Arrow::Buffer::shrink_to_fit = false
-    // underlying buffer only keeps growing. Resize to a smaller size does not reallocate.
-    PARQUET_THROW_NOT_OK(dest_buffer->Resize(max_compressed_size, false));
-
-    int64_t compressed_size;
-    PARQUET_THROW_NOT_OK(
-        compressor_->Compress(src_buffer.size(), src_buffer.data(), max_compressed_size,
-                              dest_buffer->mutable_data(), &compressed_size));
-    PARQUET_THROW_NOT_OK(dest_buffer->Resize(compressed_size, false));
-  }
-
-  int64_t WriteDataPage(const CompressedDataPage& page) override {
-    int64_t uncompressed_size = page.uncompressed_size();
-    std::shared_ptr<Buffer> compressed_data = page.buffer();
-
-    format::DataPageHeader data_page_header;
-    data_page_header.__set_num_values(page.num_values());
-    data_page_header.__set_encoding(ToThrift(page.encoding()));
-    data_page_header.__set_definition_level_encoding(
-        ToThrift(page.definition_level_encoding()));
-    data_page_header.__set_repetition_level_encoding(
-        ToThrift(page.repetition_level_encoding()));
-    data_page_header.__set_statistics(ToThrift(page.statistics()));
-
-    format::PageHeader page_header;
-    page_header.__set_type(format::PageType::DATA_PAGE);
-    page_header.__set_uncompressed_page_size(static_cast<int32_t>(uncompressed_size));
-    page_header.__set_compressed_page_size(static_cast<int32_t>(compressed_data->size()));
-    page_header.__set_data_page_header(data_page_header);
-    // TODO(PARQUET-594) crc checksum
-
-    int64_t start_pos = sink_->Tell();
-    if (data_page_offset_ == 0) {
-      data_page_offset_ = start_pos;
-    }
-
-    int64_t header_size =
-        SerializeThriftMsg(&page_header, sizeof(format::PageHeader), sink_);
-    sink_->Write(compressed_data->data(), compressed_data->size());
-
-    total_uncompressed_size_ += uncompressed_size + header_size;
-    total_compressed_size_ += compressed_data->size() + header_size;
-    num_values_ += page.num_values();
-
-    return sink_->Tell() - start_pos;
-  }
-
-  bool has_compressor() override { return (compressor_ != nullptr); }
-
-  int64_t num_values() { return num_values_; }
-
-  int64_t dictionary_page_offset() { return dictionary_page_offset_; }
-
-  int64_t data_page_offset() { return data_page_offset_; }
-
-  int64_t total_compressed_size() { return total_compressed_size_; }
-
-  int64_t total_uncompressed_size() { return total_uncompressed_size_; }
-
- private:
-  OutputStream* sink_;
-  ColumnChunkMetaDataBuilder* metadata_;
-  ::arrow::MemoryPool* pool_;
-  int64_t num_values_;
-  int64_t dictionary_page_offset_;
-  int64_t data_page_offset_;
-  int64_t total_uncompressed_size_;
-  int64_t total_compressed_size_;
-
-  // Compression codec to use.
-  std::unique_ptr<::arrow::Codec> compressor_;
-};
-
-// This implementation of the PageWriter writes to the final sink on Close .
-class BufferedPageWriter : public PageWriter {
- public:
-  BufferedPageWriter(OutputStream* sink, Compression::type codec,
-                     ColumnChunkMetaDataBuilder* metadata,
-                     ::arrow::MemoryPool* pool = ::arrow::default_memory_pool())
-      : final_sink_(sink),
-        metadata_(metadata),
-        in_memory_sink_(new InMemoryOutputStream(pool)),
-        pager_(new SerializedPageWriter(in_memory_sink_.get(), codec, metadata, pool)) {}
-
-  int64_t WriteDictionaryPage(const DictionaryPage& page) override {
-    return pager_->WriteDictionaryPage(page);
-  }
-
-  void Close(bool has_dictionary, bool fallback) override {
-    // index_page_offset = -1 since they are not supported
-    metadata_->Finish(
-        pager_->num_values(), pager_->dictionary_page_offset() + final_sink_->Tell(), -1,
-        pager_->data_page_offset() + final_sink_->Tell(), pager_->total_compressed_size(),
-        pager_->total_uncompressed_size(), has_dictionary, fallback);
-
-    // Write metadata at end of column chunk
-    metadata_->WriteTo(in_memory_sink_.get());
-
-    // flush everything to the serialized sink
-    auto buffer = in_memory_sink_->GetBuffer();
-    final_sink_->Write(buffer->data(), buffer->size());
-  }
-
-  int64_t WriteDataPage(const CompressedDataPage& page) override {
-    return pager_->WriteDataPage(page);
-  }
-
-  void Compress(const Buffer& src_buffer, ResizableBuffer* dest_buffer) override {
-    pager_->Compress(src_buffer, dest_buffer);
-  }
-
-  bool has_compressor() override { return pager_->has_compressor(); }
-
- private:
-  OutputStream* final_sink_;
-  ColumnChunkMetaDataBuilder* metadata_;
-  std::unique_ptr<InMemoryOutputStream> in_memory_sink_;
-  std::unique_ptr<SerializedPageWriter> pager_;
-};
-
-std::unique_ptr<PageWriter> PageWriter::Open(OutputStream* sink, Compression::type codec,
-                                             ColumnChunkMetaDataBuilder* metadata,
-                                             ::arrow::MemoryPool* pool,
-                                             bool buffered_row_group) {
-  if (buffered_row_group) {
-    return std::unique_ptr<PageWriter>(
-        new BufferedPageWriter(sink, codec, metadata, pool));
-  } else {
-    return std::unique_ptr<PageWriter>(
-        new SerializedPageWriter(sink, codec, metadata, pool));
-  }
-}
-
-// ----------------------------------------------------------------------
-// ColumnWriter
-
-std::shared_ptr<WriterProperties> default_writer_properties() {
-  static std::shared_ptr<WriterProperties> default_writer_properties =
-      WriterProperties::Builder().build();
-  return default_writer_properties;
-}
-
-ColumnWriter::ColumnWriter(ColumnChunkMetaDataBuilder* metadata,
-                           std::unique_ptr<PageWriter> pager, bool has_dictionary,
-                           Encoding::type encoding, const WriterProperties* properties)
-    : metadata_(metadata),
-      descr_(metadata->descr()),
-      pager_(std::move(pager)),
-      has_dictionary_(has_dictionary),
-      encoding_(encoding),
-      properties_(properties),
-      allocator_(properties->memory_pool()),
-      pool_(properties->memory_pool()),
-      num_buffered_values_(0),
-      num_buffered_encoded_values_(0),
-      rows_written_(0),
-      total_bytes_written_(0),
-      total_compressed_bytes_(0),
-      closed_(false),
-      fallback_(false) {
-  definition_levels_sink_.reset(new InMemoryOutputStream(allocator_));
-  repetition_levels_sink_.reset(new InMemoryOutputStream(allocator_));
-  definition_levels_rle_ =
-      std::static_pointer_cast<ResizableBuffer>(AllocateBuffer(allocator_, 0));
-  repetition_levels_rle_ =
-      std::static_pointer_cast<ResizableBuffer>(AllocateBuffer(allocator_, 0));
-  uncompressed_data_ =
-      std::static_pointer_cast<ResizableBuffer>(AllocateBuffer(allocator_, 0));
-  if (pager_->has_compressor()) {
-    compressed_data_ =
-        std::static_pointer_cast<ResizableBuffer>(AllocateBuffer(allocator_, 0));
-  }
-}
-
-void ColumnWriter::InitSinks() {
-  definition_levels_sink_->Clear();
-  repetition_levels_sink_->Clear();
-}
-
-void ColumnWriter::WriteDefinitionLevels(int64_t num_levels, const int16_t* levels) {
-  DCHECK(!closed_);
-  definition_levels_sink_->Write(reinterpret_cast<const uint8_t*>(levels),
-                                 sizeof(int16_t) * num_levels);
-}
-
-void ColumnWriter::WriteRepetitionLevels(int64_t num_levels, const int16_t* levels) {
-  DCHECK(!closed_);
-  repetition_levels_sink_->Write(reinterpret_cast<const uint8_t*>(levels),
-                                 sizeof(int16_t) * num_levels);
-}
-
-// return the size of the encoded buffer
-int64_t ColumnWriter::RleEncodeLevels(const Buffer& src_buffer,
-                                      ResizableBuffer* dest_buffer, int16_t max_level) {
-  // TODO: This only works with due to some RLE specifics
-  int64_t rle_size = LevelEncoder::MaxBufferSize(Encoding::RLE, max_level,
-                                                 static_cast<int>(num_buffered_values_)) +
-                     sizeof(int32_t);
-
-  // Use Arrow::Buffer::shrink_to_fit = false
-  // underlying buffer only keeps growing. Resize to a smaller size does not reallocate.
-  PARQUET_THROW_NOT_OK(dest_buffer->Resize(rle_size, false));
-
-  level_encoder_.Init(Encoding::RLE, max_level, static_cast<int>(num_buffered_values_),
-                      dest_buffer->mutable_data() + sizeof(int32_t),
-                      static_cast<int>(dest_buffer->size() - sizeof(int32_t)));
-  int encoded =
-      level_encoder_.Encode(static_cast<int>(num_buffered_values_),
-                            reinterpret_cast<const int16_t*>(src_buffer.data()));
-  DCHECK_EQ(encoded, num_buffered_values_);
-  reinterpret_cast<int32_t*>(dest_buffer->mutable_data())[0] = level_encoder_.len();
-  int64_t encoded_size = level_encoder_.len() + sizeof(int32_t);
-  return encoded_size;
-}
-
-void ColumnWriter::AddDataPage() {
-  int64_t definition_levels_rle_size = 0;
-  int64_t repetition_levels_rle_size = 0;
-
-  std::shared_ptr<Buffer> values = GetValuesBuffer();
-
-  if (descr_->max_definition_level() > 0) {
-    definition_levels_rle_size =
-        RleEncodeLevels(definition_levels_sink_->GetBufferRef(),
-                        definition_levels_rle_.get(), descr_->max_definition_level());
-  }
-
-  if (descr_->max_repetition_level() > 0) {
-    repetition_levels_rle_size =
-        RleEncodeLevels(repetition_levels_sink_->GetBufferRef(),
-                        repetition_levels_rle_.get(), descr_->max_repetition_level());
-  }
-
-  int64_t uncompressed_size =
-      definition_levels_rle_size + repetition_levels_rle_size + values->size();
-
-  // Use Arrow::Buffer::shrink_to_fit = false
-  // underlying buffer only keeps growing. Resize to a smaller size does not reallocate.
-  PARQUET_THROW_NOT_OK(uncompressed_data_->Resize(uncompressed_size, false));
-
-  // Concatenate data into a single buffer
-  uint8_t* uncompressed_ptr = uncompressed_data_->mutable_data();
-  memcpy(uncompressed_ptr, repetition_levels_rle_->data(), repetition_levels_rle_size);
-  uncompressed_ptr += repetition_levels_rle_size;
-  memcpy(uncompressed_ptr, definition_levels_rle_->data(), definition_levels_rle_size);
-  uncompressed_ptr += definition_levels_rle_size;
-  memcpy(uncompressed_ptr, values->data(), values->size());
-
-  EncodedStatistics page_stats = GetPageStatistics();
-  ResetPageStatistics();
-
-  std::shared_ptr<Buffer> compressed_data;
-  if (pager_->has_compressor()) {
-    pager_->Compress(*(uncompressed_data_.get()), compressed_data_.get());
-    compressed_data = compressed_data_;
-  } else {
-    compressed_data = uncompressed_data_;
-  }
-
-  // Write the page to OutputStream eagerly if there is no dictionary or
-  // if dictionary encoding has fallen back to PLAIN
-  if (has_dictionary_ && !fallback_) {  // Save pages until end of dictionary encoding
-    std::shared_ptr<Buffer> compressed_data_copy;
-    PARQUET_THROW_NOT_OK(compressed_data->Copy(0, compressed_data->size(), allocator_,
-                                               &compressed_data_copy));
-    CompressedDataPage page(compressed_data_copy,
-                            static_cast<int32_t>(num_buffered_values_), encoding_,
-                            Encoding::RLE, Encoding::RLE, uncompressed_size, page_stats);
-    total_compressed_bytes_ += page.size() + sizeof(format::PageHeader);
-    data_pages_.push_back(std::move(page));
-  } else {  // Eagerly write pages
-    CompressedDataPage page(compressed_data, static_cast<int32_t>(num_buffered_values_),
-                            encoding_, Encoding::RLE, Encoding::RLE, uncompressed_size,
-                            page_stats);
-    WriteDataPage(page);
-  }
-
-  // Re-initialize the sinks for next Page.
-  InitSinks();
-  num_buffered_values_ = 0;
-  num_buffered_encoded_values_ = 0;
-}
-
-void ColumnWriter::WriteDataPage(const CompressedDataPage& page) {
-  total_bytes_written_ += pager_->WriteDataPage(page);
-}
-
-int64_t ColumnWriter::Close() {
-  if (!closed_) {
-    closed_ = true;
-    if (has_dictionary_ && !fallback_) {
-      WriteDictionaryPage();
-    }
-
-    FlushBufferedDataPages();
-
-    EncodedStatistics chunk_statistics = GetChunkStatistics();
-    // Write stats only if the column has at least one row written
-    // From parquet-mr
-    // Don't write stats larger than the max size rather than truncating. The
-    // rationale is that some engines may use the minimum value in the page as
-    // the true minimum for aggregations and there is no way to mark that a
-    // value has been truncated and is a lower bound and not in the page.
-    if (rows_written_ > 0 && chunk_statistics.is_set() &&
-        chunk_statistics.max_stat_length() <=
-            properties_->max_statistics_size(descr_->path())) {
-      metadata_->SetStatistics(SortOrder::SIGNED == descr_->sort_order(),
-                               chunk_statistics);
-    }
-    pager_->Close(has_dictionary_, fallback_);
-  }
-
-  return total_bytes_written_;
-}
-
-void ColumnWriter::FlushBufferedDataPages() {
-  // Write all outstanding data to a new page
-  if (num_buffered_values_ > 0) {
-    AddDataPage();
-  }
-  for (size_t i = 0; i < data_pages_.size(); i++) {
-    WriteDataPage(data_pages_[i]);
-  }
-  data_pages_.clear();
-  total_compressed_bytes_ = 0;
-}
-
-// ----------------------------------------------------------------------
-// TypedColumnWriter
-
-template <typename Type>
-TypedColumnWriter<Type>::TypedColumnWriter(ColumnChunkMetaDataBuilder* metadata,
-                                           std::unique_ptr<PageWriter> pager,
-                                           Encoding::type encoding,
-                                           const WriterProperties* properties)
-    : ColumnWriter(metadata, std::move(pager),
-                   (encoding == Encoding::PLAIN_DICTIONARY ||
-                    encoding == Encoding::RLE_DICTIONARY),
-                   encoding, properties) {
-  switch (encoding) {
-    case Encoding::PLAIN:
-      current_encoder_.reset(new PlainEncoder<Type>(descr_, properties->memory_pool()));
-      break;
-    case Encoding::PLAIN_DICTIONARY:
-    case Encoding::RLE_DICTIONARY:
-      current_encoder_.reset(
-          new DictEncoder<Type>(descr_, &pool_, properties->memory_pool()));
-      break;
-    default:
-      ParquetException::NYI("Selected encoding is not supported");
-  }
-
-  if (properties->statistics_enabled(descr_->path()) &&
-      (SortOrder::UNKNOWN != descr_->sort_order())) {
-    page_statistics_ = std::unique_ptr<TypedStats>(new TypedStats(descr_, allocator_));
-    chunk_statistics_ = std::unique_ptr<TypedStats>(new TypedStats(descr_, allocator_));
-  }
-}
-
-// Only one Dictionary Page is written.
-// Fallback to PLAIN if dictionary page limit is reached.
-template <typename Type>
-void TypedColumnWriter<Type>::CheckDictionarySizeLimit() {
-  auto dict_encoder = static_cast<DictEncoder<Type>*>(current_encoder_.get());
-  if (dict_encoder->dict_encoded_size() >= properties_->dictionary_pagesize_limit()) {
-    WriteDictionaryPage();
-    // Serialize the buffered Dictionary Indicies
-    FlushBufferedDataPages();
-    fallback_ = true;
-    // Only PLAIN encoding is supported for fallback in V1
-    current_encoder_.reset(new PlainEncoder<Type>(descr_, properties_->memory_pool()));
-    encoding_ = Encoding::PLAIN;
-  }
-}
-
-template <typename Type>
-void TypedColumnWriter<Type>::WriteDictionaryPage() {
-  auto dict_encoder = static_cast<DictEncoder<Type>*>(current_encoder_.get());
-  std::shared_ptr<ResizableBuffer> buffer =
-      AllocateBuffer(properties_->memory_pool(), dict_encoder->dict_encoded_size());
-  dict_encoder->WriteDict(buffer->mutable_data());
-  // TODO Get rid of this deep call
-  dict_encoder->mem_pool()->FreeAll();
-
-  DictionaryPage page(buffer, dict_encoder->num_entries(),
-                      properties_->dictionary_index_encoding());
-  total_bytes_written_ += pager_->WriteDictionaryPage(page);
-}
-
-template <typename Type>
-EncodedStatistics TypedColumnWriter<Type>::GetPageStatistics() {
-  EncodedStatistics result;
-  if (page_statistics_) result = page_statistics_->Encode();
-  return result;
-}
-
-template <typename Type>
-EncodedStatistics TypedColumnWriter<Type>::GetChunkStatistics() {
-  EncodedStatistics result;
-  if (chunk_statistics_) result = chunk_statistics_->Encode();
-  return result;
-}
-
-template <typename Type>
-void TypedColumnWriter<Type>::ResetPageStatistics() {
-  if (chunk_statistics_ != nullptr) {
-    chunk_statistics_->Merge(*page_statistics_);
-    page_statistics_->Reset();
-  }
-}
-
-// ----------------------------------------------------------------------
-// Dynamic column writer constructor
-
-std::shared_ptr<ColumnWriter> ColumnWriter::Make(ColumnChunkMetaDataBuilder* metadata,
-                                                 std::unique_ptr<PageWriter> pager,
-                                                 const WriterProperties* properties) {
-  const ColumnDescriptor* descr = metadata->descr();
-  Encoding::type encoding = properties->encoding(descr->path());
-  if (properties->dictionary_enabled(descr->path()) &&
-      descr->physical_type() != Type::BOOLEAN) {
-    encoding = properties->dictionary_page_encoding();
-  }
-  switch (descr->physical_type()) {
-    case Type::BOOLEAN:
-      return std::make_shared<BoolWriter>(metadata, std::move(pager), encoding,
-                                          properties);
-    case Type::INT32:
-      return std::make_shared<Int32Writer>(metadata, std::move(pager), encoding,
-                                           properties);
-    case Type::INT64:
-      return std::make_shared<Int64Writer>(metadata, std::move(pager), encoding,
-                                           properties);
-    case Type::INT96:
-      return std::make_shared<Int96Writer>(metadata, std::move(pager), encoding,
-                                           properties);
-    case Type::FLOAT:
-      return std::make_shared<FloatWriter>(metadata, std::move(pager), encoding,
-                                           properties);
-    case Type::DOUBLE:
-      return std::make_shared<DoubleWriter>(metadata, std::move(pager), encoding,
-                                            properties);
-    case Type::BYTE_ARRAY:
-      return std::make_shared<ByteArrayWriter>(metadata, std::move(pager), encoding,
-                                               properties);
-    case Type::FIXED_LEN_BYTE_ARRAY:
-      return std::make_shared<FixedLenByteArrayWriter>(metadata, std::move(pager),
-                                                       encoding, properties);
-    default:
-      ParquetException::NYI("type reader not implemented");
-  }
-  // Unreachable code, but supress compiler warning
-  return std::shared_ptr<ColumnWriter>(nullptr);
-}
-
-// ----------------------------------------------------------------------
-// Instantiate templated classes
-
-template <typename DType>
-inline int64_t TypedColumnWriter<DType>::WriteMiniBatch(int64_t num_values,
-                                                        const int16_t* def_levels,
-                                                        const int16_t* rep_levels,
-                                                        const T* values) {
-  int64_t values_to_write = 0;
-  // If the field is required and non-repeated, there are no definition levels
-  if (descr_->max_definition_level() > 0) {
-    for (int64_t i = 0; i < num_values; ++i) {
-      if (def_levels[i] == descr_->max_definition_level()) {
-        ++values_to_write;
-      }
-    }
-
-    WriteDefinitionLevels(num_values, def_levels);
-  } else {
-    // Required field, write all values
-    values_to_write = num_values;
-  }
-
-  // Not present for non-repeated fields
-  if (descr_->max_repetition_level() > 0) {
-    // A row could include more than one value
-    // Count the occasions where we start a new row
-    for (int64_t i = 0; i < num_values; ++i) {
-      if (rep_levels[i] == 0) {
-        rows_written_++;
-      }
-    }
-
-    WriteRepetitionLevels(num_values, rep_levels);
-  } else {
-    // Each value is exactly one row
-    rows_written_ += static_cast<int>(num_values);
-  }
-
-  // PARQUET-780
-  if (values_to_write > 0) {
-    DCHECK(nullptr != values) << "Values ptr cannot be NULL";
-  }
-
-  WriteValues(values_to_write, values);
-
-  if (page_statistics_ != nullptr) {
-    page_statistics_->Update(values, values_to_write, num_values - values_to_write);
-  }
-
-  num_buffered_values_ += num_values;
-  num_buffered_encoded_values_ += values_to_write;
-
-  if (current_encoder_->EstimatedDataEncodedSize() >= properties_->data_pagesize()) {
-    AddDataPage();
-  }
-  if (has_dictionary_ && !fallback_) {
-    CheckDictionarySizeLimit();
-  }
-
-  return values_to_write;
-}
-
-template <typename DType>
-inline int64_t TypedColumnWriter<DType>::WriteMiniBatchSpaced(
-    int64_t num_values, const int16_t* def_levels, const int16_t* rep_levels,
-    const uint8_t* valid_bits, int64_t valid_bits_offset, const T* values,
-    int64_t* num_spaced_written) {
-  int64_t values_to_write = 0;
-  int64_t spaced_values_to_write = 0;
-  // If the field is required and non-repeated, there are no definition levels
-  if (descr_->max_definition_level() > 0) {
-    // Minimal definition level for which spaced values are written
-    int16_t min_spaced_def_level = descr_->max_definition_level();
-    if (descr_->schema_node()->is_optional()) {
-      min_spaced_def_level--;
-    }
-    for (int64_t i = 0; i < num_values; ++i) {
-      if (def_levels[i] == descr_->max_definition_level()) {
-        ++values_to_write;
-      }
-      if (def_levels[i] >= min_spaced_def_level) {
-        ++spaced_values_to_write;
-      }
-    }
-
-    WriteDefinitionLevels(num_values, def_levels);
-  } else {
-    // Required field, write all values
-    values_to_write = num_values;
-    spaced_values_to_write = num_values;
-  }
-
-  // Not present for non-repeated fields
-  if (descr_->max_repetition_level() > 0) {
-    // A row could include more than one value
-    // Count the occasions where we start a new row
-    for (int64_t i = 0; i < num_values; ++i) {
-      if (rep_levels[i] == 0) {
-        rows_written_++;
-      }
-    }
-
-    WriteRepetitionLevels(num_values, rep_levels);
-  } else {
-    // Each value is exactly one row
-    rows_written_ += static_cast<int>(num_values);
-  }
-
-  if (descr_->schema_node()->is_optional()) {
-    WriteValuesSpaced(spaced_values_to_write, valid_bits, valid_bits_offset, values);
-  } else {
-    WriteValues(values_to_write, values);
-  }
-  *num_spaced_written = spaced_values_to_write;
-
-  if (page_statistics_ != nullptr) {
-    page_statistics_->UpdateSpaced(values, valid_bits, valid_bits_offset, values_to_write,
-                                   num_values - values_to_write);
-  }
-
-  num_buffered_values_ += num_values;
-  num_buffered_encoded_values_ += values_to_write;
-
-  if (current_encoder_->EstimatedDataEncodedSize() >= properties_->data_pagesize()) {
-    AddDataPage();
-  }
-  if (has_dictionary_ && !fallback_) {
-    CheckDictionarySizeLimit();
-  }
-
-  return values_to_write;
-}
-
-template <typename DType>
-void TypedColumnWriter<DType>::WriteBatch(int64_t num_values, const int16_t* def_levels,
-                                          const int16_t* rep_levels, const T* values) {
-  // We check for DataPage limits only after we have inserted the values. If a user
-  // writes a large number of values, the DataPage size can be much above the limit.
-  // The purpose of this chunking is to bound this. Even if a user writes large number
-  // of values, the chunking will ensure the AddDataPage() is called at a reasonable
-  // pagesize limit
-  int64_t write_batch_size = properties_->write_batch_size();
-  int num_batches = static_cast<int>(num_values / write_batch_size);
-  int64_t num_remaining = num_values % write_batch_size;
-  int64_t value_offset = 0;
-  for (int round = 0; round < num_batches; round++) {
-    int64_t offset = round * write_batch_size;
-    int64_t num_values = WriteMiniBatch(write_batch_size, &def_levels[offset],
-                                        &rep_levels[offset], &values[value_offset]);
-    value_offset += num_values;
-  }
-  // Write the remaining values
-  int64_t offset = num_batches * write_batch_size;
-  WriteMiniBatch(num_remaining, &def_levels[offset], &rep_levels[offset],
-                 &values[value_offset]);
-}
-
-template <typename DType>
-void TypedColumnWriter<DType>::WriteBatchSpaced(
-    int64_t num_values, const int16_t* def_levels, const int16_t* rep_levels,
-    const uint8_t* valid_bits, int64_t valid_bits_offset, const T* values) {
-  // We check for DataPage limits only after we have inserted the values. If a user
-  // writes a large number of values, the DataPage size can be much above the limit.
-  // The purpose of this chunking is to bound this. Even if a user writes large number
-  // of values, the chunking will ensure the AddDataPage() is called at a reasonable
-  // pagesize limit
-  int64_t write_batch_size = properties_->write_batch_size();
-  int num_batches = static_cast<int>(num_values / write_batch_size);
-  int64_t num_remaining = num_values % write_batch_size;
-  int64_t num_spaced_written = 0;
-  int64_t values_offset = 0;
-  for (int round = 0; round < num_batches; round++) {
-    int64_t offset = round * write_batch_size;
-    WriteMiniBatchSpaced(write_batch_size, &def_levels[offset], &rep_levels[offset],
-                         valid_bits, valid_bits_offset + values_offset,
-                         values + values_offset, &num_spaced_written);
-    values_offset += num_spaced_written;
-  }
-  // Write the remaining values
-  int64_t offset = num_batches * write_batch_size;
-  WriteMiniBatchSpaced(num_remaining, &def_levels[offset], &rep_levels[offset],
-                       valid_bits, valid_bits_offset + values_offset,
-                       values + values_offset, &num_spaced_written);
-}
-
-template <typename DType>
-void TypedColumnWriter<DType>::WriteValues(int64_t num_values, const T* values) {
-  current_encoder_->Put(values, static_cast<int>(num_values));
-}
-
-template <typename DType>
-void TypedColumnWriter<DType>::WriteValuesSpaced(int64_t num_values,
-                                                 const uint8_t* valid_bits,
-                                                 int64_t valid_bits_offset,
-                                                 const T* values) {
-  current_encoder_->PutSpaced(values, static_cast<int>(num_values), valid_bits,
-                              valid_bits_offset);
-}
-
-template class PARQUET_TEMPLATE_EXPORT TypedColumnWriter<BooleanType>;
-template class PARQUET_TEMPLATE_EXPORT TypedColumnWriter<Int32Type>;
-template class PARQUET_TEMPLATE_EXPORT TypedColumnWriter<Int64Type>;
-template class PARQUET_TEMPLATE_EXPORT TypedColumnWriter<Int96Type>;
-template class PARQUET_TEMPLATE_EXPORT TypedColumnWriter<FloatType>;
-template class PARQUET_TEMPLATE_EXPORT TypedColumnWriter<DoubleType>;
-template class PARQUET_TEMPLATE_EXPORT TypedColumnWriter<ByteArrayType>;
-template class PARQUET_TEMPLATE_EXPORT TypedColumnWriter<FLBAType>;
-
-}  // namespace parquet
diff --git a/src/parquet/column_writer.h b/src/parquet/column_writer.h
deleted file mode 100644
index 1ba428a..0000000
--- a/src/parquet/column_writer.h
+++ /dev/null
@@ -1,328 +0,0 @@
-// 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.
-
-#ifndef PARQUET_COLUMN_WRITER_H
-#define PARQUET_COLUMN_WRITER_H
-
-#include <vector>
-
-#include "parquet/column_page.h"
-#include "parquet/encoding.h"
-#include "parquet/metadata.h"
-#include "parquet/properties.h"
-#include "parquet/schema.h"
-#include "parquet/statistics.h"
-#include "parquet/types.h"
-#include "parquet/util/memory.h"
-#include "parquet/util/visibility.h"
-
-namespace arrow {
-
-class BitWriter;
-class RleEncoder;
-
-}  // namespace arrow
-
-namespace parquet {
-
-class PARQUET_EXPORT LevelEncoder {
- public:
-  LevelEncoder();
-  ~LevelEncoder();
-
-  static int MaxBufferSize(Encoding::type encoding, int16_t max_level,
-                           int num_buffered_values);
-
-  // Initialize the LevelEncoder.
-  void Init(Encoding::type encoding, int16_t max_level, int num_buffered_values,
-            uint8_t* data, int data_size);
-
-  // Encodes a batch of levels from an array and returns the number of levels encoded
-  int Encode(int batch_size, const int16_t* levels);
-
-  int32_t len() {
-    if (encoding_ != Encoding::RLE) {
-      throw ParquetException("Only implemented for RLE encoding");
-    }
-    return rle_length_;
-  }
-
- private:
-  int bit_width_;
-  int rle_length_;
-  Encoding::type encoding_;
-  std::unique_ptr<::arrow::RleEncoder> rle_encoder_;
-  std::unique_ptr<::arrow::BitWriter> bit_packed_encoder_;
-};
-
-class PageWriter {
- public:
-  virtual ~PageWriter() {}
-
-  static std::unique_ptr<PageWriter> Open(
-      OutputStream* sink, Compression::type codec, ColumnChunkMetaDataBuilder* metadata,
-      ::arrow::MemoryPool* pool = ::arrow::default_memory_pool(),
-      bool buffered_row_group = false);
-
-  // The Column Writer decides if dictionary encoding is used if set and
-  // if the dictionary encoding has fallen back to default encoding on reaching dictionary
-  // page limit
-  virtual void Close(bool has_dictionary, bool fallback) = 0;
-
-  virtual int64_t WriteDataPage(const CompressedDataPage& page) = 0;
-
-  virtual int64_t WriteDictionaryPage(const DictionaryPage& page) = 0;
-
-  virtual bool has_compressor() = 0;
-
-  virtual void Compress(const Buffer& src_buffer, ResizableBuffer* dest_buffer) = 0;
-};
-
-static constexpr int WRITE_BATCH_SIZE = 1000;
-class PARQUET_EXPORT ColumnWriter {
- public:
-  ColumnWriter(ColumnChunkMetaDataBuilder*, std::unique_ptr<PageWriter>,
-               bool has_dictionary, Encoding::type encoding,
-               const WriterProperties* properties);
-
-  virtual ~ColumnWriter() = default;
-
-  static std::shared_ptr<ColumnWriter> Make(ColumnChunkMetaDataBuilder*,
-                                            std::unique_ptr<PageWriter>,
-                                            const WriterProperties* properties);
-
-  Type::type type() const { return descr_->physical_type(); }
-
-  const ColumnDescriptor* descr() const { return descr_; }
-
-  /**
-   * Closes the ColumnWriter, commits any buffered values to pages.
-   *
-   * @return Total size of the column in bytes
-   */
-  int64_t Close();
-
-  int64_t rows_written() const { return rows_written_; }
-
-  // Only considers the size of the compressed pages + page header
-  // Some values might be still buffered an not written to a page yet
-  int64_t total_compressed_bytes() const { return total_compressed_bytes_; }
-
-  int64_t total_bytes_written() const { return total_bytes_written_; }
-
-  const WriterProperties* properties() { return properties_; }
-
- protected:
-  virtual std::shared_ptr<Buffer> GetValuesBuffer() = 0;
-
-  // Serializes Dictionary Page if enabled
-  virtual void WriteDictionaryPage() = 0;
-
-  // Checks if the Dictionary Page size limit is reached
-  // If the limit is reached, the Dictionary and Data Pages are serialized
-  // The encoding is switched to PLAIN
-
-  virtual void CheckDictionarySizeLimit() = 0;
-
-  // Plain-encoded statistics of the current page
-  virtual EncodedStatistics GetPageStatistics() = 0;
-
-  // Plain-encoded statistics of the whole chunk
-  virtual EncodedStatistics GetChunkStatistics() = 0;
-
-  // Merges page statistics into chunk statistics, then resets the values
-  virtual void ResetPageStatistics() = 0;
-
-  // Adds Data Pages to an in memory buffer in dictionary encoding mode
-  // Serializes the Data Pages in other encoding modes
-  void AddDataPage();
-
-  // Serializes Data Pages
-  void WriteDataPage(const CompressedDataPage& page);
-
-  // Write multiple definition levels
-  void WriteDefinitionLevels(int64_t num_levels, const int16_t* levels);
-
-  // Write multiple repetition levels
-  void WriteRepetitionLevels(int64_t num_levels, const int16_t* levels);
-
-  // RLE encode the src_buffer into dest_buffer and return the encoded size
-  int64_t RleEncodeLevels(const Buffer& src_buffer, ResizableBuffer* dest_buffer,
-                          int16_t max_level);
-
-  // Serialize the buffered Data Pages
-  void FlushBufferedDataPages();
-
-  ColumnChunkMetaDataBuilder* metadata_;
-  const ColumnDescriptor* descr_;
-
-  std::unique_ptr<PageWriter> pager_;
-
-  bool has_dictionary_;
-  Encoding::type encoding_;
-  const WriterProperties* properties_;
-
-  LevelEncoder level_encoder_;
-
-  ::arrow::MemoryPool* allocator_;
-  ChunkedAllocator pool_;
-
-  // The total number of values stored in the data page. This is the maximum of
-  // the number of encoded definition levels or encoded values. For
-  // non-repeated, required columns, this is equal to the number of encoded
-  // values. For repeated or optional values, there may be fewer data values
-  // than levels, and this tells you how many encoded levels there are in that
-  // case.
-  int64_t num_buffered_values_;
-
-  // The total number of stored values. For repeated or optional values, this
-  // number may be lower than num_buffered_values_.
-  int64_t num_buffered_encoded_values_;
-
-  // Total number of rows written with this ColumnWriter
-  int rows_written_;
-
-  // Records the total number of bytes written by the serializer
-  int64_t total_bytes_written_;
-
-  // Records the current number of compressed bytes in a column
-  int64_t total_compressed_bytes_;
-
-  // Flag to check if the Writer has been closed
-  bool closed_;
-
-  // Flag to infer if dictionary encoding has fallen back to PLAIN
-  bool fallback_;
-
-  std::unique_ptr<InMemoryOutputStream> definition_levels_sink_;
-  std::unique_ptr<InMemoryOutputStream> repetition_levels_sink_;
-
-  std::shared_ptr<ResizableBuffer> definition_levels_rle_;
-  std::shared_ptr<ResizableBuffer> repetition_levels_rle_;
-
-  std::shared_ptr<ResizableBuffer> uncompressed_data_;
-  std::shared_ptr<ResizableBuffer> compressed_data_;
-
-  std::vector<CompressedDataPage> data_pages_;
-
- private:
-  void InitSinks();
-};
-
-// API to write values to a single column. This is the main client facing API.
-template <typename DType>
-class PARQUET_EXPORT TypedColumnWriter : public ColumnWriter {
- public:
-  typedef typename DType::c_type T;
-
-  TypedColumnWriter(ColumnChunkMetaDataBuilder* metadata,
-                    std::unique_ptr<PageWriter> pager, Encoding::type encoding,
-                    const WriterProperties* properties);
-
-  // Write a batch of repetition levels, definition levels, and values to the
-  // column.
-  void WriteBatch(int64_t num_values, const int16_t* def_levels,
-                  const int16_t* rep_levels, const T* values);
-
-  /// Write a batch of repetition levels, definition levels, and values to the
-  /// column.
-  ///
-  /// In comparision to WriteBatch the length of repetition and definition levels
-  /// is the same as of the number of values read for max_definition_level == 1.
-  /// In the case of max_definition_level > 1, the repetition and definition
-  /// levels are larger than the values but the values include the null entries
-  /// with definition_level == (max_definition_level - 1). Thus we have to differentiate
-  /// in the parameters of this function if the input has the length of num_values or the
-  /// _number of rows in the lowest nesting level_.
-  ///
-  /// In the case that the most inner node in the Parquet is required, the _number of rows
-  /// in the lowest nesting level_ is equal to the number of non-null values. If the
-  /// inner-most schema node is optional, the _number of rows in the lowest nesting level_
-  /// also includes all values with definition_level == (max_definition_level - 1).
-  ///
-  /// @param num_values number of levels to write.
-  /// @param def_levels The Parquet definiton levels, length is num_values
-  /// @param rep_levels The Parquet repetition levels, length is num_values
-  /// @param valid_bits Bitmap that indicates if the row is null on the lowest nesting
-  ///   level. The length is number of rows in the lowest nesting level.
-  /// @param valid_bits_offset The offset in bits of the valid_bits where the
-  ///   first relevant bit resides.
-  /// @param values The values in the lowest nested level including
-  ///   spacing for nulls on the lowest levels; input has the length
-  ///   of the number of rows on the lowest nesting level.
-  void WriteBatchSpaced(int64_t num_values, const int16_t* def_levels,
-                        const int16_t* rep_levels, const uint8_t* valid_bits,
-                        int64_t valid_bits_offset, const T* values);
-
-  // Estimated size of the values that are not written to a page yet
-  int64_t EstimatedBufferedValueBytes() const {
-    return current_encoder_->EstimatedDataEncodedSize();
-  }
-
- protected:
-  std::shared_ptr<Buffer> GetValuesBuffer() override {
-    return current_encoder_->FlushValues();
-  }
-  void WriteDictionaryPage() override;
-  void CheckDictionarySizeLimit() override;
-  EncodedStatistics GetPageStatistics() override;
-  EncodedStatistics GetChunkStatistics() override;
-  void ResetPageStatistics() override;
-
- private:
-  int64_t WriteMiniBatch(int64_t num_values, const int16_t* def_levels,
-                         const int16_t* rep_levels, const T* values);
-
-  int64_t WriteMiniBatchSpaced(int64_t num_values, const int16_t* def_levels,
-                               const int16_t* rep_levels, const uint8_t* valid_bits,
-                               int64_t valid_bits_offset, const T* values,
-                               int64_t* num_spaced_written);
-
-  typedef Encoder<DType> EncoderType;
-
-  // Write values to a temporary buffer before they are encoded into pages
-  void WriteValues(int64_t num_values, const T* values);
-  void WriteValuesSpaced(int64_t num_values, const uint8_t* valid_bits,
-                         int64_t valid_bits_offset, const T* values);
-  std::unique_ptr<EncoderType> current_encoder_;
-
-  typedef TypedRowGroupStatistics<DType> TypedStats;
-  std::unique_ptr<TypedStats> page_statistics_;
-  std::unique_ptr<TypedStats> chunk_statistics_;
-};
-
-typedef TypedColumnWriter<BooleanType> BoolWriter;
-typedef TypedColumnWriter<Int32Type> Int32Writer;
-typedef TypedColumnWriter<Int64Type> Int64Writer;
-typedef TypedColumnWriter<Int96Type> Int96Writer;
-typedef TypedColumnWriter<FloatType> FloatWriter;
-typedef TypedColumnWriter<DoubleType> DoubleWriter;
-typedef TypedColumnWriter<ByteArrayType> ByteArrayWriter;
-typedef TypedColumnWriter<FLBAType> FixedLenByteArrayWriter;
-
-extern template class PARQUET_EXPORT TypedColumnWriter<BooleanType>;
-extern template class PARQUET_EXPORT TypedColumnWriter<Int32Type>;
-extern template class PARQUET_EXPORT TypedColumnWriter<Int64Type>;
-extern template class PARQUET_EXPORT TypedColumnWriter<Int96Type>;
-extern template class PARQUET_EXPORT TypedColumnWriter<FloatType>;
-extern template class PARQUET_EXPORT TypedColumnWriter<DoubleType>;
-extern template class PARQUET_EXPORT TypedColumnWriter<ByteArrayType>;
-extern template class PARQUET_EXPORT TypedColumnWriter<FLBAType>;
-
-}  // namespace parquet
-
-#endif  // PARQUET_COLUMN_READER_H
diff --git a/src/parquet/encoding-benchmark.cc b/src/parquet/encoding-benchmark.cc
deleted file mode 100644
index 364cdba..0000000
--- a/src/parquet/encoding-benchmark.cc
+++ /dev/null
@@ -1,166 +0,0 @@
-// 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.
-
-#include "benchmark/benchmark.h"
-
-#include "parquet/encoding-internal.h"
-#include "parquet/util/memory.h"
-
-using arrow::default_memory_pool;
-using arrow::MemoryPool;
-
-namespace parquet {
-
-using schema::PrimitiveNode;
-
-namespace benchmark {
-
-std::shared_ptr<ColumnDescriptor> Int64Schema(Repetition::type repetition) {
-  auto node = PrimitiveNode::Make("int64", repetition, Type::INT64);
-  return std::make_shared<ColumnDescriptor>(node, repetition != Repetition::REQUIRED,
-                                            repetition == Repetition::REPEATED);
-}
-
-static void BM_PlainEncodingBoolean(::benchmark::State& state) {
-  std::vector<bool> values(state.range(0), 64);
-  PlainEncoder<BooleanType> encoder(nullptr);
-
-  while (state.KeepRunning()) {
-    encoder.Put(values, static_cast<int>(values.size()));
-    encoder.FlushValues();
-  }
-  state.SetBytesProcessed(state.iterations() * state.range(0) * sizeof(bool));
-}
-
-BENCHMARK(BM_PlainEncodingBoolean)->Range(1024, 65536);
-
-static void BM_PlainDecodingBoolean(::benchmark::State& state) {
-  std::vector<bool> values(state.range(0), 64);
-  bool* output = new bool[state.range(0)];
-  PlainEncoder<BooleanType> encoder(nullptr);
-  encoder.Put(values, static_cast<int>(values.size()));
-  std::shared_ptr<Buffer> buf = encoder.FlushValues();
-
-  while (state.KeepRunning()) {
-    PlainDecoder<BooleanType> decoder(nullptr);
-    decoder.SetData(static_cast<int>(values.size()), buf->data(),
-                    static_cast<int>(buf->size()));
-    decoder.Decode(output, static_cast<int>(values.size()));
-  }
-
-  state.SetBytesProcessed(state.iterations() * state.range(0) * sizeof(bool));
-  delete[] output;
-}
-
-BENCHMARK(BM_PlainDecodingBoolean)->Range(1024, 65536);
-
-static void BM_PlainEncodingInt64(::benchmark::State& state) {
-  std::vector<int64_t> values(state.range(0), 64);
-  PlainEncoder<Int64Type> encoder(nullptr);
-
-  while (state.KeepRunning()) {
-    encoder.Put(values.data(), static_cast<int>(values.size()));
-    encoder.FlushValues();
-  }
-  state.SetBytesProcessed(state.iterations() * state.range(0) * sizeof(int64_t));
-}
-
-BENCHMARK(BM_PlainEncodingInt64)->Range(1024, 65536);
-
-static void BM_PlainDecodingInt64(::benchmark::State& state) {
-  std::vector<int64_t> values(state.range(0), 64);
-  PlainEncoder<Int64Type> encoder(nullptr);
-  encoder.Put(values.data(), static_cast<int>(values.size()));
-  std::shared_ptr<Buffer> buf = encoder.FlushValues();
-
-  while (state.KeepRunning()) {
-    PlainDecoder<Int64Type> decoder(nullptr);
-    decoder.SetData(static_cast<int>(values.size()), buf->data(),
-                    static_cast<int>(buf->size()));
-    decoder.Decode(values.data(), static_cast<int>(values.size()));
-  }
-  state.SetBytesProcessed(state.iterations() * state.range(0) * sizeof(int64_t));
-}
-
-BENCHMARK(BM_PlainDecodingInt64)->Range(1024, 65536);
-
-template <typename Type>
-static void DecodeDict(std::vector<typename Type::c_type>& values,
-                       ::benchmark::State& state) {
-  typedef typename Type::c_type T;
-  int num_values = static_cast<int>(values.size());
-
-  ChunkedAllocator pool;
-  MemoryPool* allocator = default_memory_pool();
-  std::shared_ptr<ColumnDescriptor> descr = Int64Schema(Repetition::REQUIRED);
-
-  DictEncoder<Type> encoder(descr.get(), &pool, allocator);
-  for (int i = 0; i < num_values; ++i) {
-    encoder.Put(values[i]);
-  }
-
-  std::shared_ptr<ResizableBuffer> dict_buffer =
-      AllocateBuffer(allocator, encoder.dict_encoded_size());
-
-  std::shared_ptr<ResizableBuffer> indices =
-      AllocateBuffer(allocator, encoder.EstimatedDataEncodedSize());
-
-  encoder.WriteDict(dict_buffer->mutable_data());
-  int actual_bytes =
-      encoder.WriteIndices(indices->mutable_data(), static_cast<int>(indices->size()));
-
-  PARQUET_THROW_NOT_OK(indices->Resize(actual_bytes));
-
-  while (state.KeepRunning()) {
-    PlainDecoder<Type> dict_decoder(descr.get());
-    dict_decoder.SetData(encoder.num_entries(), dict_buffer->data(),
-                         static_cast<int>(dict_buffer->size()));
-    DictionaryDecoder<Type> decoder(descr.get());
-    decoder.SetDict(&dict_decoder);
-    decoder.SetData(num_values, indices->data(), static_cast<int>(indices->size()));
-    decoder.Decode(values.data(), num_values);
-  }
-
-  state.SetBytesProcessed(state.iterations() * state.range(0) * sizeof(T));
-}
-
-static void BM_DictDecodingInt64_repeats(::benchmark::State& state) {
-  typedef Int64Type Type;
-  typedef typename Type::c_type T;
-
-  std::vector<T> values(state.range(0), 64);
-  DecodeDict<Type>(values, state);
-}
-
-BENCHMARK(BM_DictDecodingInt64_repeats)->Range(1024, 65536);
-
-static void BM_DictDecodingInt64_literals(::benchmark::State& state) {
-  typedef Int64Type Type;
-  typedef typename Type::c_type T;
-
-  std::vector<T> values(state.range(0));
-  for (size_t i = 0; i < values.size(); ++i) {
-    values[i] = i;
-  }
-  DecodeDict<Type>(values, state);
-}
-
-BENCHMARK(BM_DictDecodingInt64_literals)->Range(1024, 65536);
-
-}  // namespace benchmark
-
-}  // namespace parquet
diff --git a/src/parquet/encoding-internal.h b/src/parquet/encoding-internal.h
deleted file mode 100644
index 2dfb9ff..0000000
--- a/src/parquet/encoding-internal.h
+++ /dev/null
@@ -1,979 +0,0 @@
-// 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.
-
-#ifndef PARQUET_ENCODING_INTERNAL_H
-#define PARQUET_ENCODING_INTERNAL_H
-
-#include <algorithm>
-#include <cstdint>
-#include <limits>
-#include <memory>
-#include <vector>
-
-#include "arrow/util/bit-stream-utils.h"
-#include "arrow/util/bit-util.h"
-#include "arrow/util/cpu-info.h"
-#include "arrow/util/hash-util.h"
-#include "arrow/util/macros.h"
-#include "arrow/util/rle-encoding.h"
-
-#include "parquet/encoding.h"
-#include "parquet/exception.h"
-#include "parquet/schema.h"
-#include "parquet/types.h"
-#include "parquet/util/memory.h"
-
-namespace parquet {
-
-namespace BitUtil = ::arrow::BitUtil;
-using HashUtil = ::arrow::HashUtil;
-
-class ColumnDescriptor;
-
-// ----------------------------------------------------------------------
-// Encoding::PLAIN decoder implementation
-
-template <typename DType>
-class PlainDecoder : public Decoder<DType> {
- public:
-  typedef typename DType::c_type T;
-  using Decoder<DType>::num_values_;
-
-  explicit PlainDecoder(const ColumnDescriptor* descr)
-      : Decoder<DType>(descr, Encoding::PLAIN), data_(nullptr), len_(0) {
-    if (descr_ && descr_->physical_type() == Type::FIXED_LEN_BYTE_ARRAY) {
-      type_length_ = descr_->type_length();
-    } else {
-      type_length_ = -1;
-    }
-  }
-
-  virtual void SetData(int num_values, const uint8_t* data, int len) {
-    num_values_ = num_values;
-    data_ = data;
-    len_ = len;
-  }
-
-  virtual int Decode(T* buffer, int max_values);
-
- private:
-  using Decoder<DType>::descr_;
-  const uint8_t* data_;
-  int len_;
-  int type_length_;
-};
-
-// Decode routine templated on C++ type rather than type enum
-template <typename T>
-inline int DecodePlain(const uint8_t* data, int64_t data_size, int num_values,
-                       int type_length, T* out) {
-  int bytes_to_decode = num_values * static_cast<int>(sizeof(T));
-  if (data_size < bytes_to_decode) {
-    ParquetException::EofException();
-  }
-  memcpy(out, data, bytes_to_decode);
-  return bytes_to_decode;
-}
-
-// Template specialization for BYTE_ARRAY. The written values do not own their
-// own data.
-template <>
-inline int DecodePlain<ByteArray>(const uint8_t* data, int64_t data_size, int num_values,
-                                  int type_length, ByteArray* out) {
-  int bytes_decoded = 0;
-  int increment;
-  for (int i = 0; i < num_values; ++i) {
-    uint32_t len = out[i].len = *reinterpret_cast<const uint32_t*>(data);
-    increment = static_cast<int>(sizeof(uint32_t) + len);
-    if (data_size < increment) ParquetException::EofException();
-    out[i].ptr = data + sizeof(uint32_t);
-    data += increment;
-    data_size -= increment;
-    bytes_decoded += increment;
-  }
-  return bytes_decoded;
-}
-
-// Template specialization for FIXED_LEN_BYTE_ARRAY. The written values do not
-// own their own data.
-template <>
-inline int DecodePlain<FixedLenByteArray>(const uint8_t* data, int64_t data_size,
-                                          int num_values, int type_length,
-                                          FixedLenByteArray* out) {
-  int bytes_to_decode = type_length * num_values;
-  if (data_size < bytes_to_decode) {
-    ParquetException::EofException();
-  }
-  for (int i = 0; i < num_values; ++i) {
-    out[i].ptr = data;
-    data += type_length;
-    data_size -= type_length;
-  }
-  return bytes_to_decode;
-}
-
-template <typename DType>
-inline int PlainDecoder<DType>::Decode(T* buffer, int max_values) {
-  max_values = std::min(max_values, num_values_);
-  int bytes_consumed = DecodePlain<T>(data_, len_, max_values, type_length_, buffer);
-  data_ += bytes_consumed;
-  len_ -= bytes_consumed;
-  num_values_ -= max_values;
-  return max_values;
-}
-
-template <>
-class PlainDecoder<BooleanType> : public Decoder<BooleanType> {
- public:
-  explicit PlainDecoder(const ColumnDescriptor* descr)
-      : Decoder<BooleanType>(descr, Encoding::PLAIN) {}
-
-  virtual void SetData(int num_values, const uint8_t* data, int len) {
-    num_values_ = num_values;
-    bit_reader_ = ::arrow::BitReader(data, len);
-  }
-
-  // Two flavors of bool decoding
-  int Decode(uint8_t* buffer, int max_values) {
-    max_values = std::min(max_values, num_values_);
-    bool val;
-    ::arrow::internal::BitmapWriter bit_writer(buffer, 0, max_values);
-    for (int i = 0; i < max_values; ++i) {
-      if (!bit_reader_.GetValue(1, &val)) {
-        ParquetException::EofException();
-      }
-      if (val) {
-        bit_writer.Set();
-      }
-      bit_writer.Next();
-    }
-    bit_writer.Finish();
-    num_values_ -= max_values;
-    return max_values;
-  }
-
-  virtual int Decode(bool* buffer, int max_values) {
-    max_values = std::min(max_values, num_values_);
-    if (bit_reader_.GetBatch(1, buffer, max_values) != max_values) {
-      ParquetException::EofException();
-    }
-    num_values_ -= max_values;
-    return max_values;
-  }
-
- private:
-  ::arrow::BitReader bit_reader_;
-};
-
-// ----------------------------------------------------------------------
-// Encoding::PLAIN encoder implementation
-
-template <typename DType>
-class PlainEncoder : public Encoder<DType> {
- public:
-  typedef typename DType::c_type T;
-
-  explicit PlainEncoder(const ColumnDescriptor* descr,
-                        ::arrow::MemoryPool* pool = ::arrow::default_memory_pool())
-      : Encoder<DType>(descr, Encoding::PLAIN, pool) {
-    values_sink_.reset(new InMemoryOutputStream(pool));
-  }
-
-  int64_t EstimatedDataEncodedSize() override { return values_sink_->Tell(); }
-
-  std::shared_ptr<Buffer> FlushValues() override;
-  void Put(const T* src, int num_values) override;
-
- protected:
-  std::unique_ptr<InMemoryOutputStream> values_sink_;
-};
-
-template <>
-class PlainEncoder<BooleanType> : public Encoder<BooleanType> {
- public:
-  explicit PlainEncoder(const ColumnDescriptor* descr,
-                        ::arrow::MemoryPool* pool = ::arrow::default_memory_pool())
-      : Encoder<BooleanType>(descr, Encoding::PLAIN, pool),
-        bits_available_(kInMemoryDefaultCapacity * 8),
-        bits_buffer_(AllocateBuffer(pool, kInMemoryDefaultCapacity)),
-        values_sink_(new InMemoryOutputStream(pool)) {
-    bit_writer_.reset(new ::arrow::BitWriter(bits_buffer_->mutable_data(),
-                                             static_cast<int>(bits_buffer_->size())));
-  }
-
-  int64_t EstimatedDataEncodedSize() override {
-    return values_sink_->Tell() + bit_writer_->bytes_written();
-  }
-
-  std::shared_ptr<Buffer> FlushValues() override {
-    if (bits_available_ > 0) {
-      bit_writer_->Flush();
-      values_sink_->Write(bit_writer_->buffer(), bit_writer_->bytes_written());
-      bit_writer_->Clear();
-      bits_available_ = static_cast<int>(bits_buffer_->size()) * 8;
-    }
-
-    std::shared_ptr<Buffer> buffer = values_sink_->GetBuffer();
-    values_sink_.reset(new InMemoryOutputStream(this->pool_));
-    return buffer;
-  }
-
-#define PLAINDECODER_BOOLEAN_PUT(input_type, function_attributes)                 \
-  void Put(input_type src, int num_values) function_attributes {                  \
-    int bit_offset = 0;                                                           \
-    if (bits_available_ > 0) {                                                    \
-      int bits_to_write = std::min(bits_available_, num_values);                  \
-      for (int i = 0; i < bits_to_write; i++) {                                   \
-        bit_writer_->PutValue(src[i], 1);                                         \
-      }                                                                           \
-      bits_available_ -= bits_to_write;                                           \
-      bit_offset = bits_to_write;                                                 \
-                                                                                  \
-      if (bits_available_ == 0) {                                                 \
-        bit_writer_->Flush();                                                     \
-        values_sink_->Write(bit_writer_->buffer(), bit_writer_->bytes_written()); \
-        bit_writer_->Clear();                                                     \
-      }                                                                           \
-    }                                                                             \
-                                                                                  \
-    int bits_remaining = num_values - bit_offset;                                 \
-    while (bit_offset < num_values) {                                             \
-      bits_available_ = static_cast<int>(bits_buffer_->size()) * 8;               \
-                                                                                  \
-      int bits_to_write = std::min(bits_available_, bits_remaining);              \
-      for (int i = bit_offset; i < bit_offset + bits_to_write; i++) {             \
-        bit_writer_->PutValue(src[i], 1);                                         \
-      }                                                                           \
-      bit_offset += bits_to_write;                                                \
-      bits_available_ -= bits_to_write;                                           \
-      bits_remaining -= bits_to_write;                                            \
-                                                                                  \
-      if (bits_available_ == 0) {                                                 \
-        bit_writer_->Flush();                                                     \
-        values_sink_->Write(bit_writer_->buffer(), bit_writer_->bytes_written()); \
-        bit_writer_->Clear();                                                     \
-      }                                                                           \
-    }                                                                             \
-  }
-
-  PLAINDECODER_BOOLEAN_PUT(const bool*, override)
-  PLAINDECODER_BOOLEAN_PUT(const std::vector<bool>&, )
-
- protected:
-  int bits_available_;
-  std::unique_ptr<::arrow::BitWriter> bit_writer_;
-  std::shared_ptr<ResizableBuffer> bits_buffer_;
-  std::unique_ptr<InMemoryOutputStream> values_sink_;
-};
-
-template <typename DType>
-inline std::shared_ptr<Buffer> PlainEncoder<DType>::FlushValues() {
-  std::shared_ptr<Buffer> buffer = values_sink_->GetBuffer();
-  values_sink_.reset(new InMemoryOutputStream(this->pool_));
-  return buffer;
-}
-
-template <typename DType>
-inline void PlainEncoder<DType>::Put(const T* buffer, int num_values) {
-  values_sink_->Write(reinterpret_cast<const uint8_t*>(buffer), num_values * sizeof(T));
-}
-
-template <>
-inline void PlainEncoder<ByteArrayType>::Put(const ByteArray* src, int num_values) {
-  for (int i = 0; i < num_values; ++i) {
-    // Write the result to the output stream
-    values_sink_->Write(reinterpret_cast<const uint8_t*>(&src[i].len), sizeof(uint32_t));
-    if (src[i].len > 0) {
-      DCHECK(nullptr != src[i].ptr) << "Value ptr cannot be NULL";
-    }
-    values_sink_->Write(reinterpret_cast<const uint8_t*>(src[i].ptr), src[i].len);
-  }
-}
-
-template <>
-inline void PlainEncoder<FLBAType>::Put(const FixedLenByteArray* src, int num_values) {
-  for (int i = 0; i < num_values; ++i) {
-    // Write the result to the output stream
-    if (descr_->type_length() > 0) {
-      DCHECK(nullptr != src[i].ptr) << "Value ptr cannot be NULL";
-    }
-    values_sink_->Write(reinterpret_cast<const uint8_t*>(src[i].ptr),
-                        descr_->type_length());
-  }
-}
-
-// ----------------------------------------------------------------------
-// Dictionary encoding and decoding
-
-template <typename Type>
-class DictionaryDecoder : public Decoder<Type> {
- public:
-  typedef typename Type::c_type T;
-
-  // Initializes the dictionary with values from 'dictionary'. The data in
-  // dictionary is not guaranteed to persist in memory after this call so the
-  // dictionary decoder needs to copy the data out if necessary.
-  explicit DictionaryDecoder(const ColumnDescriptor* descr,
-                             ::arrow::MemoryPool* pool = ::arrow::default_memory_pool())
-      : Decoder<Type>(descr, Encoding::RLE_DICTIONARY),
-        dictionary_(0, pool),
-        byte_array_data_(AllocateBuffer(pool, 0)) {}
-
-  // Perform type-specific initiatialization
-  void SetDict(Decoder<Type>* dictionary);
-
-  void SetData(int num_values, const uint8_t* data, int len) override {
-    num_values_ = num_values;
-    if (len == 0) return;
-    uint8_t bit_width = *data;
-    ++data;
-    --len;
-    idx_decoder_ = ::arrow::RleDecoder(data, len, bit_width);
-  }
-
-  int Decode(T* buffer, int max_values) override {
-    max_values = std::min(max_values, num_values_);
-    int decoded_values =
-        idx_decoder_.GetBatchWithDict(dictionary_.data(), buffer, max_values);
-    if (decoded_values != max_values) {
-      ParquetException::EofException();
-    }
-    num_values_ -= max_values;
-    return max_values;
-  }
-
-  int DecodeSpaced(T* buffer, int num_values, int null_count, const uint8_t* valid_bits,
-                   int64_t valid_bits_offset) override {
-    int decoded_values =
-        idx_decoder_.GetBatchWithDictSpaced(dictionary_.data(), buffer, num_values,
-                                            null_count, valid_bits, valid_bits_offset);
-    if (decoded_values != num_values) {
-      ParquetException::EofException();
-    }
-    return decoded_values;
-  }
-
- private:
-  using Decoder<Type>::num_values_;
-
-  // Only one is set.
-  Vector<T> dictionary_;
-
-  // Data that contains the byte array data (byte_array_dictionary_ just has the
-  // pointers).
-  std::shared_ptr<ResizableBuffer> byte_array_data_;
-
-  ::arrow::RleDecoder idx_decoder_;
-};
-
-template <typename Type>
-inline void DictionaryDecoder<Type>::SetDict(Decoder<Type>* dictionary) {
-  int num_dictionary_values = dictionary->values_left();
-  dictionary_.Resize(num_dictionary_values);
-  dictionary->Decode(&dictionary_[0], num_dictionary_values);
-}
-
-template <>
-inline void DictionaryDecoder<BooleanType>::SetDict(Decoder<BooleanType>* dictionary) {
-  ParquetException::NYI("Dictionary encoding is not implemented for boolean values");
-}
-
-template <>
-inline void DictionaryDecoder<ByteArrayType>::SetDict(
-    Decoder<ByteArrayType>* dictionary) {
-  int num_dictionary_values = dictionary->values_left();
-  dictionary_.Resize(num_dictionary_values);
-  dictionary->Decode(&dictionary_[0], num_dictionary_values);
-
-  int total_size = 0;
-  for (int i = 0; i < num_dictionary_values; ++i) {
-    total_size += dictionary_[i].len;
-  }
-  if (total_size > 0) {
-    PARQUET_THROW_NOT_OK(byte_array_data_->Resize(total_size, false));
-  }
-
-  int offset = 0;
-  uint8_t* bytes_data = byte_array_data_->mutable_data();
-  for (int i = 0; i < num_dictionary_values; ++i) {
-    memcpy(bytes_data + offset, dictionary_[i].ptr, dictionary_[i].len);
-    dictionary_[i].ptr = bytes_data + offset;
-    offset += dictionary_[i].len;
-  }
-}
-
-template <>
-inline void DictionaryDecoder<FLBAType>::SetDict(Decoder<FLBAType>* dictionary) {
-  int num_dictionary_values = dictionary->values_left();
-  dictionary_.Resize(num_dictionary_values);
-  dictionary->Decode(&dictionary_[0], num_dictionary_values);
-
-  int fixed_len = descr_->type_length();
-  int total_size = num_dictionary_values * fixed_len;
-
-  PARQUET_THROW_NOT_OK(byte_array_data_->Resize(total_size, false));
-  uint8_t* bytes_data = byte_array_data_->mutable_data();
-  for (int32_t i = 0, offset = 0; i < num_dictionary_values; ++i, offset += fixed_len) {
-    memcpy(bytes_data + offset, dictionary_[i].ptr, fixed_len);
-    dictionary_[i].ptr = bytes_data + offset;
-  }
-}
-
-// ----------------------------------------------------------------------
-// Dictionary encoder
-
-// Initially imported from Apache Impala on 2016-02-22, and has been modified
-// since for parquet-cpp
-
-// Initially 1024 elements
-static constexpr int INITIAL_HASH_TABLE_SIZE = 1 << 10;
-
-typedef int32_t hash_slot_t;
-static constexpr hash_slot_t HASH_SLOT_EMPTY = std::numeric_limits<int32_t>::max();
-
-// The maximum load factor for the hash table before resizing.
-static constexpr double MAX_HASH_LOAD = 0.7;
-
-/// See the dictionary encoding section of https://github.com/Parquet/parquet-format.
-/// The encoding supports streaming encoding. Values are encoded as they are added while
-/// the dictionary is being constructed. At any time, the buffered values can be
-/// written out with the current dictionary size. More values can then be added to
-/// the encoder, including new dictionary entries.
-template <typename DType>
-class DictEncoder : public Encoder<DType> {
- public:
-  typedef typename DType::c_type T;
-
-  explicit DictEncoder(const ColumnDescriptor* desc, ChunkedAllocator* pool = nullptr,
-                       ::arrow::MemoryPool* allocator = ::arrow::default_memory_pool())
-      : Encoder<DType>(desc, Encoding::PLAIN_DICTIONARY, allocator),
-        allocator_(allocator),
-        pool_(pool),
-        hash_table_size_(INITIAL_HASH_TABLE_SIZE),
-        mod_bitmask_(hash_table_size_ - 1),
-        hash_slots_(0, allocator),
-        dict_encoded_size_(0),
-        type_length_(desc->type_length()) {
-    hash_slots_.Assign(hash_table_size_, HASH_SLOT_EMPTY);
-    if (!::arrow::CpuInfo::initialized()) {
-      ::arrow::CpuInfo::Init();
-    }
-  }
-
-  ~DictEncoder() override { DCHECK(buffered_indices_.empty()); }
-
-  // TODO(wesm): think about how to address the construction semantics in
-  // encodings/dictionary-encoding.h
-  void set_mem_pool(ChunkedAllocator* pool) { pool_ = pool; }
-
-  void set_type_length(int type_length) { type_length_ = type_length; }
-
-  /// Returns a conservative estimate of the number of bytes needed to encode the buffered
-  /// indices. Used to size the buffer passed to WriteIndices().
-  int64_t EstimatedDataEncodedSize() override {
-    // Note: because of the way RleEncoder::CheckBufferFull() is called, we have to
-    // reserve
-    // an extra "RleEncoder::MinBufferSize" bytes. These extra bytes won't be used
-    // but not reserving them would cause the encoder to fail.
-    return 1 +
-           ::arrow::RleEncoder::MaxBufferSize(
-               bit_width(), static_cast<int>(buffered_indices_.size())) +
-           ::arrow::RleEncoder::MinBufferSize(bit_width());
-  }
-
-  /// The minimum bit width required to encode the currently buffered indices.
-  int bit_width() const {
-    if (ARROW_PREDICT_FALSE(num_entries() == 0)) return 0;
-    if (ARROW_PREDICT_FALSE(num_entries() == 1)) return 1;
-    return BitUtil::Log2(num_entries());
-  }
-
-  /// Writes out any buffered indices to buffer preceded by the bit width of this data.
-  /// Returns the number of bytes written.
-  /// If the supplied buffer is not big enough, returns -1.
-  /// buffer must be preallocated with buffer_len bytes. Use EstimatedDataEncodedSize()
-  /// to size buffer.
-  int WriteIndices(uint8_t* buffer, int buffer_len);
-
-  int hash_table_size() { return hash_table_size_; }
-  int dict_encoded_size() { return dict_encoded_size_; }
-  /// Clears all the indices (but leaves the dictionary).
-  void ClearIndices() { buffered_indices_.clear(); }
-
-  /// Encode value. Note that this does not actually write any data, just
-  /// buffers the value's index to be written later.
-  void Put(const T& value);
-
-  std::shared_ptr<Buffer> FlushValues() override {
-    std::shared_ptr<ResizableBuffer> buffer =
-        AllocateBuffer(this->allocator_, EstimatedDataEncodedSize());
-    int result_size = WriteIndices(buffer->mutable_data(),
-                                   static_cast<int>(EstimatedDataEncodedSize()));
-    ClearIndices();
-    PARQUET_THROW_NOT_OK(buffer->Resize(result_size, false));
-    return buffer;
-  }
-
-  void Put(const T* values, int num_values) override {
-    for (int i = 0; i < num_values; i++) {
-      Put(values[i]);
-    }
-  }
-
-  void PutSpaced(const T* src, int num_values, const uint8_t* valid_bits,
-                 int64_t valid_bits_offset) override {
-    ::arrow::internal::BitmapReader valid_bits_reader(valid_bits, valid_bits_offset,
-                                                      num_values);
-    for (int32_t i = 0; i < num_values; i++) {
-      if (valid_bits_reader.IsSet()) {
-        Put(src[i]);
-      }
-      valid_bits_reader.Next();
-    }
-  }
-
-  /// Writes out the encoded dictionary to buffer. buffer must be preallocated to
-  /// dict_encoded_size() bytes.
-  void WriteDict(uint8_t* buffer);
-
-  ChunkedAllocator* mem_pool() { return pool_; }
-
-  /// The number of entries in the dictionary.
-  int num_entries() const { return static_cast<int>(uniques_.size()); }
-
- private:
-  ::arrow::MemoryPool* allocator_;
-
-  // For ByteArray / FixedLenByteArray data. Not owned
-  ChunkedAllocator* pool_;
-
-  /// Size of the table. Must be a power of 2.
-  int hash_table_size_;
-
-  // Store hash_table_size_ - 1, so that j & mod_bitmask_ is equivalent to j %
-  // hash_table_size_, but uses far fewer CPU cycles
-  int mod_bitmask_;
-
-  // We use a fixed-size hash table with linear probing
-  //
-  // These values correspond to the uniques_ array
-  Vector<hash_slot_t> hash_slots_;
-
-  /// Indices that have not yet be written out by WriteIndices().
-  std::vector<int> buffered_indices_;
-
-  /// The number of bytes needed to encode the dictionary.
-  int dict_encoded_size_;
-
-  // The unique observed values
-  std::vector<T> uniques_;
-
-  bool SlotDifferent(const T& v, hash_slot_t slot);
-  void DoubleTableSize();
-
-  /// Size of each encoded dictionary value. -1 for variable-length types.
-  int type_length_;
-
-  /// Hash function for mapping a value to a bucket.
-  inline int Hash(const T& value) const;
-
-  /// Adds value to the hash table and updates dict_encoded_size_
-  void AddDictKey(const T& value);
-};
-
-template <typename DType>
-inline int DictEncoder<DType>::Hash(const typename DType::c_type& value) const {
-  return HashUtil::Hash(&value, sizeof(value), 0);
-}
-
-template <>
-inline int DictEncoder<ByteArrayType>::Hash(const ByteArray& value) const {
-  if (value.len > 0) {
-    DCHECK_NE(nullptr, value.ptr) << "Value ptr cannot be NULL";
-  }
-  return HashUtil::Hash(value.ptr, value.len, 0);
-}
-
-template <>
-inline int DictEncoder<FLBAType>::Hash(const FixedLenByteArray& value) const {
-  if (type_length_ > 0) {
-    DCHECK_NE(nullptr, value.ptr) << "Value ptr cannot be NULL";
-  }
-  return HashUtil::Hash(value.ptr, type_length_, 0);
-}
-
-template <typename DType>
-inline bool DictEncoder<DType>::SlotDifferent(const typename DType::c_type& v,
-                                              hash_slot_t slot) {
-  return v != uniques_[slot];
-}
-
-template <>
-inline bool DictEncoder<FLBAType>::SlotDifferent(const FixedLenByteArray& v,
-                                                 hash_slot_t slot) {
-  return 0 != memcmp(v.ptr, uniques_[slot].ptr, type_length_);
-}
-
-template <typename DType>
-inline void DictEncoder<DType>::Put(const typename DType::c_type& v) {
-  int j = Hash(v) & mod_bitmask_;
-  hash_slot_t index = hash_slots_[j];
-
-  // Find an empty slot
-  while (HASH_SLOT_EMPTY != index && SlotDifferent(v, index)) {
-    // Linear probing
-    ++j;
-    if (j == hash_table_size_) j = 0;
-    index = hash_slots_[j];
-  }
-
-  if (index == HASH_SLOT_EMPTY) {
-    // Not in the hash table, so we insert it now
-    index = static_cast<hash_slot_t>(uniques_.size());
-    hash_slots_[j] = index;
-    AddDictKey(v);
-
-    if (ARROW_PREDICT_FALSE(static_cast<int>(uniques_.size()) >
-                            hash_table_size_ * MAX_HASH_LOAD)) {
-      DoubleTableSize();
-    }
-  }
-
-  buffered_indices_.push_back(index);
-}
-
-template <typename DType>
-inline void DictEncoder<DType>::DoubleTableSize() {
-  int new_size = hash_table_size_ * 2;
-  Vector<hash_slot_t> new_hash_slots(0, allocator_);
-  new_hash_slots.Assign(new_size, HASH_SLOT_EMPTY);
-  hash_slot_t index, slot;
-  int j;
-  for (int i = 0; i < hash_table_size_; ++i) {
-    index = hash_slots_[i];
-
-    if (index == HASH_SLOT_EMPTY) {
-      continue;
-    }
-
-    // Compute the hash value mod the new table size to start looking for an
-    // empty slot
-    const typename DType::c_type& v = uniques_[index];
-
-    // Find an empty slot in the new hash table
-    j = Hash(v) & (new_size - 1);
-    slot = new_hash_slots[j];
-    while (HASH_SLOT_EMPTY != slot && SlotDifferent(v, slot)) {
-      ++j;
-      if (j == new_size) j = 0;
-      slot = new_hash_slots[j];
-    }
-
-    // Copy the old slot index to the new hash table
-    new_hash_slots[j] = index;
-  }
-
-  hash_table_size_ = new_size;
-  mod_bitmask_ = new_size - 1;
-
-  hash_slots_.Swap(new_hash_slots);
-}
-
-template <typename DType>
-inline void DictEncoder<DType>::AddDictKey(const typename DType::c_type& v) {
-  uniques_.push_back(v);
-  dict_encoded_size_ += static_cast<int>(sizeof(typename DType::c_type));
-}
-
-template <>
-inline void DictEncoder<ByteArrayType>::AddDictKey(const ByteArray& v) {
-  uint8_t* heap = pool_->Allocate(v.len);
-  if (ARROW_PREDICT_FALSE(v.len > 0 && heap == nullptr)) {
-    throw ParquetException("out of memory");
-  }
-  memcpy(heap, v.ptr, v.len);
-  uniques_.push_back(ByteArray(v.len, heap));
-  dict_encoded_size_ += static_cast<int>(v.len + sizeof(uint32_t));
-}
-
-template <>
-inline void DictEncoder<FLBAType>::AddDictKey(const FixedLenByteArray& v) {
-  uint8_t* heap = pool_->Allocate(type_length_);
-  if (ARROW_PREDICT_FALSE(type_length_ > 0 && heap == nullptr)) {
-    throw ParquetException("out of memory");
-  }
-  memcpy(heap, v.ptr, type_length_);
-
-  uniques_.push_back(FixedLenByteArray(heap));
-  dict_encoded_size_ += type_length_;
-}
-
-template <typename DType>
-inline void DictEncoder<DType>::WriteDict(uint8_t* buffer) {
-  // For primitive types, only a memcpy
-  memcpy(buffer, uniques_.data(), sizeof(typename DType::c_type) * uniques_.size());
-}
-
-template <>
-inline void DictEncoder<BooleanType>::WriteDict(uint8_t* buffer) {
-  // For primitive types, only a memcpy
-  // memcpy(buffer, uniques_.data(), sizeof(typename DType::c_type) * uniques_.size());
-  for (size_t i = 0; i < uniques_.size(); i++) {
-    buffer[i] = uniques_[i];
-  }
-}
-
-// ByteArray and FLBA already have the dictionary encoded in their data heaps
-template <>
-inline void DictEncoder<ByteArrayType>::WriteDict(uint8_t* buffer) {
-  for (const ByteArray& v : uniques_) {
-    memcpy(buffer, reinterpret_cast<const void*>(&v.len), sizeof(uint32_t));
-    buffer += sizeof(uint32_t);
-    if (v.len > 0) {
-      DCHECK(nullptr != v.ptr) << "Value ptr cannot be NULL";
-    }
-    memcpy(buffer, v.ptr, v.len);
-    buffer += v.len;
-  }
-}
-
-template <>
-inline void DictEncoder<FLBAType>::WriteDict(uint8_t* buffer) {
-  for (const FixedLenByteArray& v : uniques_) {
-    if (type_length_ > 0) {
-      DCHECK(nullptr != v.ptr) << "Value ptr cannot be NULL";
-    }
-    memcpy(buffer, v.ptr, type_length_);
-    buffer += type_length_;
-  }
-}
-
-template <typename DType>
-inline int DictEncoder<DType>::WriteIndices(uint8_t* buffer, int buffer_len) {
-  // Write bit width in first byte
-  *buffer = static_cast<uint8_t>(bit_width());
-  ++buffer;
-  --buffer_len;
-
-  ::arrow::RleEncoder encoder(buffer, buffer_len, bit_width());
-  for (int index : buffered_indices_) {
-    if (!encoder.Put(index)) return -1;
-  }
-  encoder.Flush();
-
-  ClearIndices();
-  return 1 + encoder.len();
-}
-
-// ----------------------------------------------------------------------
-// DeltaBitPackDecoder
-
-template <typename DType>
-class DeltaBitPackDecoder : public Decoder<DType> {
- public:
-  typedef typename DType::c_type T;
-
-  explicit DeltaBitPackDecoder(const ColumnDescriptor* descr,
-                               ::arrow::MemoryPool* pool = ::arrow::default_memory_pool())
-      : Decoder<DType>(descr, Encoding::DELTA_BINARY_PACKED), pool_(pool) {
-    if (DType::type_num != Type::INT32 && DType::type_num != Type::INT64) {
-      throw ParquetException("Delta bit pack encoding should only be for integer data.");
-    }
-  }
-
-  virtual void SetData(int num_values, const uint8_t* data, int len) {
-    num_values_ = num_values;
-    decoder_ = ::arrow::BitReader(data, len);
-    values_current_block_ = 0;
-    values_current_mini_block_ = 0;
-  }
-
-  virtual int Decode(T* buffer, int max_values) {
-    return GetInternal(buffer, max_values);
-  }
-
- private:
-  using Decoder<DType>::num_values_;
-
-  void InitBlock() {
-    int32_t block_size;
-    if (!decoder_.GetVlqInt(&block_size)) ParquetException::EofException();
-    if (!decoder_.GetVlqInt(&num_mini_blocks_)) ParquetException::EofException();
-    if (!decoder_.GetVlqInt(&values_current_block_)) {
-      ParquetException::EofException();
-    }
-    if (!decoder_.GetZigZagVlqInt(&last_value_)) ParquetException::EofException();
-
-    delta_bit_widths_ = AllocateBuffer(pool_, num_mini_blocks_);
-    uint8_t* bit_width_data = delta_bit_widths_->mutable_data();
-
-    if (!decoder_.GetZigZagVlqInt(&min_delta_)) ParquetException::EofException();
-    for (int i = 0; i < num_mini_blocks_; ++i) {
-      if (!decoder_.GetAligned<uint8_t>(1, bit_width_data + i)) {
-        ParquetException::EofException();
-      }
-    }
-    values_per_mini_block_ = block_size / num_mini_blocks_;
-    mini_block_idx_ = 0;
-    delta_bit_width_ = bit_width_data[0];
-    values_current_mini_block_ = values_per_mini_block_;
-  }
-
-  template <typename T>
-  int GetInternal(T* buffer, int max_values) {
-    max_values = std::min(max_values, num_values_);
-    const uint8_t* bit_width_data = delta_bit_widths_->data();
-    for (int i = 0; i < max_values; ++i) {
-      if (ARROW_PREDICT_FALSE(values_current_mini_block_ == 0)) {
-        ++mini_block_idx_;
-        if (mini_block_idx_ < static_cast<size_t>(delta_bit_widths_->size())) {
-          delta_bit_width_ = bit_width_data[mini_block_idx_];
-          values_current_mini_block_ = values_per_mini_block_;
-        } else {
-          InitBlock();
-          buffer[i] = last_value_;
-          continue;
-        }
-      }
-
-      // TODO: the key to this algorithm is to decode the entire miniblock at once.
-      int64_t delta;
-      if (!decoder_.GetValue(delta_bit_width_, &delta)) ParquetException::EofException();
-      delta += min_delta_;
-      last_value_ += static_cast<int32_t>(delta);
-      buffer[i] = last_value_;
-      --values_current_mini_block_;
-    }
-    num_values_ -= max_values;
-    return max_values;
-  }
-
-  ::arrow::MemoryPool* pool_;
-  ::arrow::BitReader decoder_;
-  int32_t values_current_block_;
-  int32_t num_mini_blocks_;
-  uint64_t values_per_mini_block_;
-  uint64_t values_current_mini_block_;
-
-  int32_t min_delta_;
-  size_t mini_block_idx_;
-  std::shared_ptr<ResizableBuffer> delta_bit_widths_;
-  int delta_bit_width_;
-
-  int32_t last_value_;
-};
-
-// ----------------------------------------------------------------------
-// DELTA_LENGTH_BYTE_ARRAY
-
-class DeltaLengthByteArrayDecoder : public Decoder<ByteArrayType> {
- public:
-  explicit DeltaLengthByteArrayDecoder(
-      const ColumnDescriptor* descr,
-      ::arrow::MemoryPool* pool = ::arrow::default_memory_pool())
-      : Decoder<ByteArrayType>(descr, Encoding::DELTA_LENGTH_BYTE_ARRAY),
-        len_decoder_(nullptr, pool) {}
-
-  virtual void SetData(int num_values, const uint8_t* data, int len) {
-    num_values_ = num_values;
-    if (len == 0) return;
-    int total_lengths_len = *reinterpret_cast<const int*>(data);
-    data += 4;
-    len_decoder_.SetData(num_values, data, total_lengths_len);
-    data_ = data + total_lengths_len;
-    len_ = len - 4 - total_lengths_len;
-  }
-
-  virtual int Decode(ByteArray* buffer, int max_values) {
-    max_values = std::min(max_values, num_values_);
-    std::vector<int> lengths(max_values);
-    len_decoder_.Decode(lengths.data(), max_values);
-    for (int i = 0; i < max_values; ++i) {
-      buffer[i].len = lengths[i];
-      buffer[i].ptr = data_;
-      data_ += lengths[i];
-      len_ -= lengths[i];
-    }
-    num_values_ -= max_values;
-    return max_values;
-  }
-
- private:
-  using Decoder<ByteArrayType>::num_values_;
-  DeltaBitPackDecoder<Int32Type> len_decoder_;
-  const uint8_t* data_;
-  int len_;
-};
-
-// ----------------------------------------------------------------------
-// DELTA_BYTE_ARRAY
-
-class DeltaByteArrayDecoder : public Decoder<ByteArrayType> {
- public:
-  explicit DeltaByteArrayDecoder(
-      const ColumnDescriptor* descr,
-      ::arrow::MemoryPool* pool = ::arrow::default_memory_pool())
-      : Decoder<ByteArrayType>(descr, Encoding::DELTA_BYTE_ARRAY),
-        prefix_len_decoder_(nullptr, pool),
-        suffix_decoder_(nullptr, pool),
-        last_value_(0, nullptr) {}
-
-  virtual void SetData(int num_values, const uint8_t* data, int len) {
-    num_values_ = num_values;
-    if (len == 0) return;
-    int prefix_len_length = *reinterpret_cast<const int*>(data);
-    data += 4;
-    len -= 4;
-    prefix_len_decoder_.SetData(num_values, data, prefix_len_length);
-    data += prefix_len_length;
-    len -= prefix_len_length;
-    suffix_decoder_.SetData(num_values, data, len);
-  }
-
-  // TODO: this doesn't work and requires memory management. We need to allocate
-  // new strings to store the results.
-  virtual int Decode(ByteArray* buffer, int max_values) {
-    max_values = std::min(max_values, num_values_);
-    for (int i = 0; i < max_values; ++i) {
-      int prefix_len = 0;
-      prefix_len_decoder_.Decode(&prefix_len, 1);
-      ByteArray suffix = {0, nullptr};
-      suffix_decoder_.Decode(&suffix, 1);
-      buffer[i].len = prefix_len + suffix.len;
-
-      uint8_t* result = reinterpret_cast<uint8_t*>(malloc(buffer[i].len));
-      memcpy(result, last_value_.ptr, prefix_len);
-      memcpy(result + prefix_len, suffix.ptr, suffix.len);
-
-      buffer[i].ptr = result;
-      last_value_ = buffer[i];
-    }
-    num_values_ -= max_values;
-    return max_values;
-  }
-
- private:
-  using Decoder<ByteArrayType>::num_values_;
-
-  DeltaBitPackDecoder<Int32Type> prefix_len_decoder_;
-  DeltaLengthByteArrayDecoder suffix_decoder_;
-  ByteArray last_value_;
-};
-
-}  // namespace parquet
-
-#endif  // PARQUET_ENCODING_INTERNAL_H
diff --git a/src/parquet/encoding-test.cc b/src/parquet/encoding-test.cc
deleted file mode 100644
index 50e1394..0000000
--- a/src/parquet/encoding-test.cc
+++ /dev/null
@@ -1,313 +0,0 @@
-// 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.
-
-#include <gtest/gtest.h>
-#include <cstdint>
-#include <cstdlib>
-#include <cstring>
-#include <string>
-#include <vector>
-
-#include "arrow/util/bit-util.h"
-
-#include "parquet/encoding-internal.h"
-#include "parquet/schema.h"
-#include "parquet/types.h"
-#include "parquet/util/memory.h"
-#include "parquet/util/test-common.h"
-
-using arrow::default_memory_pool;
-using arrow::MemoryPool;
-
-using std::string;
-using std::vector;
-
-namespace parquet {
-
-namespace test {
-
-TEST(VectorBooleanTest, TestEncodeDecode) {
-  // PARQUET-454
-  int nvalues = 10000;
-  int nbytes = static_cast<int>(BitUtil::BytesForBits(nvalues));
-
-  // seed the prng so failure is deterministic
-  vector<bool> draws = flip_coins_seed(nvalues, 0.5, 0);
-
-  PlainEncoder<BooleanType> encoder(nullptr);
-  PlainDecoder<BooleanType> decoder(nullptr);
-
-  encoder.Put(draws, nvalues);
-
-  std::shared_ptr<Buffer> encode_buffer = encoder.FlushValues();
-  ASSERT_EQ(nbytes, encode_buffer->size());
-
-  vector<uint8_t> decode_buffer(nbytes);
-  const uint8_t* decode_data = &decode_buffer[0];
-
-  decoder.SetData(nvalues, encode_buffer->data(),
-                  static_cast<int>(encode_buffer->size()));
-  int values_decoded = decoder.Decode(&decode_buffer[0], nvalues);
-  ASSERT_EQ(nvalues, values_decoded);
-
-  for (int i = 0; i < nvalues; ++i) {
-    ASSERT_EQ(draws[i], BitUtil::GetBit(decode_data, i)) << i;
-  }
-}
-
-// ----------------------------------------------------------------------
-// test data generation
-
-template <typename T>
-void GenerateData(int num_values, T* out, vector<uint8_t>* heap) {
-  // seed the prng so failure is deterministic
-  random_numbers(num_values, 0, std::numeric_limits<T>::min(),
-                 std::numeric_limits<T>::max(), out);
-}
-
-template <>
-void GenerateData<bool>(int num_values, bool* out, vector<uint8_t>* heap) {
-  // seed the prng so failure is deterministic
-  random_bools(num_values, 0.5, 0, out);
-}
-
-template <>
-void GenerateData<Int96>(int num_values, Int96* out, vector<uint8_t>* heap) {
-  // seed the prng so failure is deterministic
-  random_Int96_numbers(num_values, 0, std::numeric_limits<int32_t>::min(),
-                       std::numeric_limits<int32_t>::max(), out);
-}
-
-template <>
-void GenerateData<ByteArray>(int num_values, ByteArray* out, vector<uint8_t>* heap) {
-  // seed the prng so failure is deterministic
-  int max_byte_array_len = 12;
-  heap->resize(num_values * max_byte_array_len);
-  random_byte_array(num_values, 0, heap->data(), out, 2, max_byte_array_len);
-}
-
-static int flba_length = 8;
-
-template <>
-void GenerateData<FLBA>(int num_values, FLBA* out, vector<uint8_t>* heap) {
-  // seed the prng so failure is deterministic
-  heap->resize(num_values * flba_length);
-  random_fixed_byte_array(num_values, 0, heap->data(), flba_length, out);
-}
-
-template <typename T>
-void VerifyResults(T* result, T* expected, int num_values) {
-  for (int i = 0; i < num_values; ++i) {
-    ASSERT_EQ(expected[i], result[i]) << i;
-  }
-}
-
-template <>
-void VerifyResults<FLBA>(FLBA* result, FLBA* expected, int num_values) {
-  for (int i = 0; i < num_values; ++i) {
-    ASSERT_EQ(0, memcmp(expected[i].ptr, result[i].ptr, flba_length)) << i;
-  }
-}
-
-// ----------------------------------------------------------------------
-// Create some column descriptors
-
-template <typename DType>
-std::shared_ptr<ColumnDescriptor> ExampleDescr() {
-  auto node = schema::PrimitiveNode::Make("name", Repetition::OPTIONAL, DType::type_num);
-  return std::make_shared<ColumnDescriptor>(node, 0, 0);
-}
-
-template <>
-std::shared_ptr<ColumnDescriptor> ExampleDescr<FLBAType>() {
-  auto node = schema::PrimitiveNode::Make("name", Repetition::OPTIONAL,
-                                          Type::FIXED_LEN_BYTE_ARRAY,
-                                          LogicalType::DECIMAL, flba_length, 10, 2);
-  return std::make_shared<ColumnDescriptor>(node, 0, 0);
-}
-
-// ----------------------------------------------------------------------
-// Plain encoding tests
-
-template <typename Type>
-class TestEncodingBase : public ::testing::Test {
- public:
-  typedef typename Type::c_type T;
-  static constexpr int TYPE = Type::type_num;
-
-  void SetUp() {
-    descr_ = ExampleDescr<Type>();
-    type_length_ = descr_->type_length();
-    allocator_ = default_memory_pool();
-  }
-
-  void TearDown() { pool_.FreeAll(); }
-
-  void InitData(int nvalues, int repeats) {
-    num_values_ = nvalues * repeats;
-    input_bytes_.resize(num_values_ * sizeof(T));
-    output_bytes_.resize(num_values_ * sizeof(T));
-    draws_ = reinterpret_cast<T*>(input_bytes_.data());
-    decode_buf_ = reinterpret_cast<T*>(output_bytes_.data());
-    GenerateData<T>(nvalues, draws_, &data_buffer_);
-
-    // add some repeated values
-    for (int j = 1; j < repeats; ++j) {
-      for (int i = 0; i < nvalues; ++i) {
-        draws_[nvalues * j + i] = draws_[i];
-      }
-    }
-  }
-
-  virtual void CheckRoundtrip() = 0;
-
-  void Execute(int nvalues, int repeats) {
-    InitData(nvalues, repeats);
-    CheckRoundtrip();
-  }
-
- protected:
-  ChunkedAllocator pool_;
-  MemoryPool* allocator_;
-
-  int num_values_;
-  int type_length_;
-  T* draws_;
-  T* decode_buf_;
-  vector<uint8_t> input_bytes_;
-  vector<uint8_t> output_bytes_;
-  vector<uint8_t> data_buffer_;
-
-  std::shared_ptr<Buffer> encode_buffer_;
-  std::shared_ptr<ColumnDescriptor> descr_;
-};
-
-// Member variables are not visible to templated subclasses. Possibly figure
-// out an alternative to this class layering at some point
-#define USING_BASE_MEMBERS()                    \
-  using TestEncodingBase<Type>::pool_;          \
-  using TestEncodingBase<Type>::allocator_;     \
-  using TestEncodingBase<Type>::descr_;         \
-  using TestEncodingBase<Type>::num_values_;    \
-  using TestEncodingBase<Type>::draws_;         \
-  using TestEncodingBase<Type>::data_buffer_;   \
-  using TestEncodingBase<Type>::type_length_;   \
-  using TestEncodingBase<Type>::encode_buffer_; \
-  using TestEncodingBase<Type>::decode_buf_
-
-template <typename Type>
-class TestPlainEncoding : public TestEncodingBase<Type> {
- public:
-  typedef typename Type::c_type T;
-  static constexpr int TYPE = Type::type_num;
-
-  virtual void CheckRoundtrip() {
-    PlainEncoder<Type> encoder(descr_.get());
-    PlainDecoder<Type> decoder(descr_.get());
-    encoder.Put(draws_, num_values_);
-    encode_buffer_ = encoder.FlushValues();
-
-    decoder.SetData(num_values_, encode_buffer_->data(),
-                    static_cast<int>(encode_buffer_->size()));
-    int values_decoded = decoder.Decode(decode_buf_, num_values_);
-    ASSERT_EQ(num_values_, values_decoded);
-    ASSERT_NO_FATAL_FAILURE(VerifyResults<T>(decode_buf_, draws_, num_values_));
-  }
-
- protected:
-  USING_BASE_MEMBERS();
-};
-
-TYPED_TEST_CASE(TestPlainEncoding, ParquetTypes);
-
-TYPED_TEST(TestPlainEncoding, BasicRoundTrip) {
-  ASSERT_NO_FATAL_FAILURE(this->Execute(10000, 1));
-}
-
-// ----------------------------------------------------------------------
-// Dictionary encoding tests
-
-typedef ::testing::Types<Int32Type, Int64Type, Int96Type, FloatType, DoubleType,
-                         ByteArrayType, FLBAType>
-    DictEncodedTypes;
-
-template <typename Type>
-class TestDictionaryEncoding : public TestEncodingBase<Type> {
- public:
-  typedef typename Type::c_type T;
-  static constexpr int TYPE = Type::type_num;
-
-  void CheckRoundtrip() {
-    std::vector<uint8_t> valid_bits(BitUtil::BytesForBits(num_values_) + 1, 255);
-    DictEncoder<Type> encoder(descr_.get(), &pool_);
-
-    ASSERT_NO_THROW(encoder.Put(draws_, num_values_));
-    dict_buffer_ = AllocateBuffer(default_memory_pool(), encoder.dict_encoded_size());
-    encoder.WriteDict(dict_buffer_->mutable_data());
-    std::shared_ptr<Buffer> indices = encoder.FlushValues();
-
-    DictEncoder<Type> spaced_encoder(descr_.get(), &pool_);
-    // PutSpaced should lead to the same results
-    ASSERT_NO_THROW(spaced_encoder.PutSpaced(draws_, num_values_, valid_bits.data(), 0));
-    std::shared_ptr<Buffer> indices_from_spaced = spaced_encoder.FlushValues();
-    ASSERT_TRUE(indices_from_spaced->Equals(*indices));
-
-    PlainDecoder<Type> dict_decoder(descr_.get());
-    dict_decoder.SetData(encoder.num_entries(), dict_buffer_->data(),
-                         static_cast<int>(dict_buffer_->size()));
-
-    DictionaryDecoder<Type> decoder(descr_.get());
-    decoder.SetDict(&dict_decoder);
-
-    decoder.SetData(num_values_, indices->data(), static_cast<int>(indices->size()));
-    int values_decoded = decoder.Decode(decode_buf_, num_values_);
-    ASSERT_EQ(num_values_, values_decoded);
-
-    // TODO(wesm): The DictionaryDecoder must stay alive because the decoded
-    // values' data is owned by a buffer inside the DictionaryEncoder. We
-    // should revisit when data lifetime is reviewed more generally.
-    ASSERT_NO_FATAL_FAILURE(VerifyResults<T>(decode_buf_, draws_, num_values_));
-
-    // Also test spaced decoding
-    decoder.SetData(num_values_, indices->data(), static_cast<int>(indices->size()));
-    values_decoded =
-        decoder.DecodeSpaced(decode_buf_, num_values_, 0, valid_bits.data(), 0);
-    ASSERT_EQ(num_values_, values_decoded);
-    ASSERT_NO_FATAL_FAILURE(VerifyResults<T>(decode_buf_, draws_, num_values_));
-  }
-
- protected:
-  USING_BASE_MEMBERS();
-  std::shared_ptr<ResizableBuffer> dict_buffer_;
-};
-
-TYPED_TEST_CASE(TestDictionaryEncoding, DictEncodedTypes);
-
-TYPED_TEST(TestDictionaryEncoding, BasicRoundTrip) {
-  ASSERT_NO_FATAL_FAILURE(this->Execute(2500, 2));
-}
-
-TEST(TestDictionaryEncoding, CannotDictDecodeBoolean) {
-  PlainDecoder<BooleanType> dict_decoder(nullptr);
-  DictionaryDecoder<BooleanType> decoder(nullptr);
-
-  ASSERT_THROW(decoder.SetDict(&dict_decoder), ParquetException);
-}
-
-}  // namespace test
-
-}  // namespace parquet
diff --git a/src/parquet/encoding.h b/src/parquet/encoding.h
deleted file mode 100644
index 006f22f..0000000
--- a/src/parquet/encoding.h
+++ /dev/null
@@ -1,152 +0,0 @@
-// 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.
-
-#ifndef PARQUET_ENCODING_H
-#define PARQUET_ENCODING_H
-
-#include <cstdint>
-#include <memory>
-#include <sstream>
-
-#include "arrow/status.h"
-#include "arrow/util/bit-util.h"
-
-#include "parquet/exception.h"
-#include "parquet/schema.h"
-#include "parquet/types.h"
-#include "parquet/util/memory.h"
-
-namespace parquet {
-
-class ColumnDescriptor;
-
-// Base class for value encoders. Since encoders may or not have state (e.g.,
-// dictionary encoding) we use a class instance to maintain any state.
-//
-// TODO(wesm): Encode interface API is temporary
-template <typename DType>
-class Encoder {
- public:
-  typedef typename DType::c_type T;
-
-  virtual ~Encoder() {}
-
-  virtual int64_t EstimatedDataEncodedSize() = 0;
-  virtual std::shared_ptr<Buffer> FlushValues() = 0;
-  virtual void Put(const T* src, int num_values) = 0;
-  virtual void PutSpaced(const T* src, int num_values, const uint8_t* valid_bits,
-                         int64_t valid_bits_offset) {
-    std::shared_ptr<ResizableBuffer> buffer;
-    auto status =
-        ::arrow::AllocateResizableBuffer(pool_, num_values * sizeof(T), &buffer);
-    if (!status.ok()) {
-      std::ostringstream ss;
-      ss << "AllocateResizableBuffer failed in Encoder.PutSpaced in " << __FILE__
-         << ", on line " << __LINE__;
-      throw ParquetException(ss.str());
-    }
-    int32_t num_valid_values = 0;
-    ::arrow::internal::BitmapReader valid_bits_reader(valid_bits, valid_bits_offset,
-                                                      num_values);
-    T* data = reinterpret_cast<T*>(buffer->mutable_data());
-    for (int32_t i = 0; i < num_values; i++) {
-      if (valid_bits_reader.IsSet()) {
-        data[num_valid_values++] = src[i];
-      }
-      valid_bits_reader.Next();
-    }
-    Put(data, num_valid_values);
-  }
-
-  Encoding::type encoding() const { return encoding_; }
-
- protected:
-  explicit Encoder(const ColumnDescriptor* descr, Encoding::type encoding,
-                   ::arrow::MemoryPool* pool)
-      : descr_(descr), encoding_(encoding), pool_(pool) {}
-
-  // For accessing type-specific metadata, like FIXED_LEN_BYTE_ARRAY
-  const ColumnDescriptor* descr_;
-  const Encoding::type encoding_;
-  ::arrow::MemoryPool* pool_;
-};
-
-// The Decoder template is parameterized on parquet::DataType subclasses
-template <typename DType>
-class Decoder {
- public:
-  typedef typename DType::c_type T;
-
-  virtual ~Decoder() {}
-
-  // Sets the data for a new page. This will be called multiple times on the same
-  // decoder and should reset all internal state.
-  virtual void SetData(int num_values, const uint8_t* data, int len) = 0;
-
-  // Subclasses should override the ones they support. In each of these functions,
-  // the decoder would decode put to 'max_values', storing the result in 'buffer'.
-  // The function returns the number of values decoded, which should be max_values
-  // except for end of the current data page.
-  virtual int Decode(T* buffer, int max_values) = 0;
-
-  // Decode the values in this data page but leave spaces for null entries.
-  //
-  // num_values is the size of the def_levels and buffer arrays including the number of
-  // null values.
-  virtual int DecodeSpaced(T* buffer, int num_values, int null_count,
-                           const uint8_t* valid_bits, int64_t valid_bits_offset) {
-    int values_to_read = num_values - null_count;
-    int values_read = Decode(buffer, values_to_read);
-    if (values_read != values_to_read) {
-      throw ParquetException("Number of values / definition_levels read did not match");
-    }
-
-    // Depending on the number of nulls, some of the value slots in buffer may
-    // be uninitialized, and this will cause valgrind warnings / potentially UB
-    memset(buffer + values_read, 0, (num_values - values_read) * sizeof(T));
-
-    // Add spacing for null entries. As we have filled the buffer from the front,
-    // we need to add the spacing from the back.
-    int values_to_move = values_read;
-    for (int i = num_values - 1; i >= 0; i--) {
-      if (::arrow::BitUtil::GetBit(valid_bits, valid_bits_offset + i)) {
-        buffer[i] = buffer[--values_to_move];
-      }
-    }
-    return num_values;
-  }
-
-  // Returns the number of values left (for the last call to SetData()). This is
-  // the number of values left in this page.
-  int values_left() const { return num_values_; }
-
-  Encoding::type encoding() const { return encoding_; }
-
- protected:
-  explicit Decoder(const ColumnDescriptor* descr, Encoding::type encoding)
-      : descr_(descr), encoding_(encoding), num_values_(0) {}
-
-  // For accessing type-specific metadata, like FIXED_LEN_BYTE_ARRAY
-  const ColumnDescriptor* descr_;
-
-  const Encoding::type encoding_;
-  int num_values_;
-};
-
-}  // namespace parquet
-
-#endif  // PARQUET_ENCODING_H
diff --git a/src/parquet/exception.cc b/src/parquet/exception.cc
deleted file mode 100644
index 5f5525c..0000000
--- a/src/parquet/exception.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-// 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.
-
-#include "parquet/exception.h"
-
-#include <exception>
-#include <sstream>
-#include <string>
-
-#include "parquet/util/macros.h"
-
-namespace parquet {
-
-PARQUET_NORETURN void ParquetException::EofException(const std::string& msg) {
-  std::stringstream ss;
-  ss << "Unexpected end of stream";
-  if (!msg.empty()) {
-    ss << ": " << msg;
-  }
-  throw ParquetException(ss.str());
-}
-
-PARQUET_NORETURN void ParquetException::NYI(const std::string& msg) {
-  std::stringstream ss;
-  ss << "Not yet implemented: " << msg << ".";
-  throw ParquetException(ss.str());
-}
-
-PARQUET_NORETURN void ParquetException::Throw(const std::string& msg) {
-  throw ParquetException(msg);
-}
-
-ParquetException::ParquetException(const char* msg) : msg_(msg) {}
-
-ParquetException::ParquetException(const std::string& msg) : msg_(msg) {}
-
-ParquetException::ParquetException(const char* msg, std::exception& e) : msg_(msg) {}
-
-ParquetException::~ParquetException() throw() {}
-
-const char* ParquetException::what() const throw() { return msg_.c_str(); }
-
-}  // namespace parquet
diff --git a/src/parquet/exception.h b/src/parquet/exception.h
deleted file mode 100644
index 08629be..0000000
--- a/src/parquet/exception.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// 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.
-
-#ifndef PARQUET_EXCEPTION_H
-#define PARQUET_EXCEPTION_H
-
-#include <exception>
-#include <sstream>
-#include <string>
-
-#include "arrow/status.h"
-
-#include "parquet/util/macros.h"
-#include "parquet/util/visibility.h"
-
-// PARQUET-1085
-#if !defined(ARROW_UNUSED)
-#define ARROW_UNUSED(x) UNUSED(x)
-#endif
-
-#define PARQUET_CATCH_NOT_OK(s)                    \
-  try {                                            \
-    (s);                                           \
-  } catch (const ::parquet::ParquetException& e) { \
-    return ::arrow::Status::IOError(e.what());     \
-  }
-
-#define PARQUET_IGNORE_NOT_OK(s) \
-  do {                           \
-    ::arrow::Status _s = (s);    \
-    ARROW_UNUSED(_s);            \
-  } while (0)
-
-#define PARQUET_THROW_NOT_OK(s)                     \
-  do {                                              \
-    ::arrow::Status _s = (s);                       \
-    if (!_s.ok()) {                                 \
-      std::stringstream ss;                         \
-      ss << "Arrow error: " << _s.ToString();       \
-      ::parquet::ParquetException::Throw(ss.str()); \
-    }                                               \
-  } while (0)
-
-namespace parquet {
-
-class PARQUET_EXPORT ParquetException : public std::exception {
- public:
-  PARQUET_NORETURN static void EofException(const std::string& msg = "");
-  PARQUET_NORETURN static void NYI(const std::string& msg);
-  PARQUET_NORETURN static void Throw(const std::string& msg);
-
-  explicit ParquetException(const char* msg);
-  explicit ParquetException(const std::string& msg);
-  explicit ParquetException(const char* msg, exception& e);
-
-  virtual ~ParquetException() throw();
-  virtual const char* what() const throw();
-
- private:
-  std::string msg_;
-};
-
-}  // namespace parquet
-
-#endif  // PARQUET_EXCEPTION_H
diff --git a/src/parquet/file-deserialize-test.cc b/src/parquet/file-deserialize-test.cc
deleted file mode 100644
index 6b01ac2..0000000
--- a/src/parquet/file-deserialize-test.cc
+++ /dev/null
@@ -1,299 +0,0 @@
-// 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.
-
-#include <gtest/gtest.h>
-
-#include <algorithm>
-#include <cstdint>
-#include <cstdlib>
-#include <cstring>
-#include <exception>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "parquet/column_reader.h"
-#include "parquet/exception.h"
-#include "parquet/file_reader.h"
-#include "parquet/parquet_types.h"
-#include "parquet/thrift.h"
-#include "parquet/types.h"
-#include "parquet/util/memory.h"
-#include "parquet/util/test-common.h"
-
-namespace parquet {
-
-#define ASSERT_OK(expr)         \
-  do {                          \
-    ::arrow::Status s = (expr); \
-    if (!s.ok()) {              \
-      FAIL() << s.ToString();   \
-    }                           \
-  } while (0)
-
-using ::arrow::io::BufferReader;
-
-// Adds page statistics occupying a certain amount of bytes (for testing very
-// large page headers)
-static inline void AddDummyStats(int stat_size, format::DataPageHeader& data_page) {
-  std::vector<uint8_t> stat_bytes(stat_size);
-  // Some non-zero value
-  std::fill(stat_bytes.begin(), stat_bytes.end(), 1);
-  data_page.statistics.__set_max(
-      std::string(reinterpret_cast<const char*>(stat_bytes.data()), stat_size));
-  data_page.__isset.statistics = true;
-}
-
-class TestPageSerde : public ::testing::Test {
- public:
-  void SetUp() {
-    data_page_header_.encoding = format::Encoding::PLAIN;
-    data_page_header_.definition_level_encoding = format::Encoding::RLE;
-    data_page_header_.repetition_level_encoding = format::Encoding::RLE;
-
-    ResetStream();
-  }
-
-  void InitSerializedPageReader(int64_t num_rows,
-                                Compression::type codec = Compression::UNCOMPRESSED) {
-    EndStream();
-    std::unique_ptr<InputStream> stream;
-    stream.reset(new InMemoryInputStream(out_buffer_));
-    page_reader_ = PageReader::Open(std::move(stream), num_rows, codec);
-  }
-
-  void WriteDataPageHeader(int max_serialized_len = 1024, int32_t uncompressed_size = 0,
-                           int32_t compressed_size = 0) {
-    // Simplifying writing serialized data page headers which may or may not
-    // have meaningful data associated with them
-
-    // Serialize the Page header
-    page_header_.__set_data_page_header(data_page_header_);
-    page_header_.uncompressed_page_size = uncompressed_size;
-    page_header_.compressed_page_size = compressed_size;
-    page_header_.type = format::PageType::DATA_PAGE;
-
-    ASSERT_NO_THROW(
-        SerializeThriftMsg(&page_header_, max_serialized_len, out_stream_.get()));
-  }
-
-  void ResetStream() { out_stream_.reset(new InMemoryOutputStream); }
-
-  void EndStream() { out_buffer_ = out_stream_->GetBuffer(); }
-
- protected:
-  std::unique_ptr<InMemoryOutputStream> out_stream_;
-  std::shared_ptr<Buffer> out_buffer_;
-
-  std::unique_ptr<PageReader> page_reader_;
-  format::PageHeader page_header_;
-  format::DataPageHeader data_page_header_;
-};
-
-void CheckDataPageHeader(const format::DataPageHeader expected, const Page* page) {
-  ASSERT_EQ(PageType::DATA_PAGE, page->type());
-
-  const DataPage* data_page = static_cast<const DataPage*>(page);
-  ASSERT_EQ(expected.num_values, data_page->num_values());
-  ASSERT_EQ(expected.encoding, data_page->encoding());
-  ASSERT_EQ(expected.definition_level_encoding, data_page->definition_level_encoding());
-  ASSERT_EQ(expected.repetition_level_encoding, data_page->repetition_level_encoding());
-
-  if (expected.statistics.__isset.max) {
-    ASSERT_EQ(expected.statistics.max, data_page->statistics().max());
-  }
-  if (expected.statistics.__isset.min) {
-    ASSERT_EQ(expected.statistics.min, data_page->statistics().min());
-  }
-}
-
-TEST_F(TestPageSerde, DataPage) {
-  format::PageHeader out_page_header;
-
-  int stats_size = 512;
-  const int32_t num_rows = 4444;
-  AddDummyStats(stats_size, data_page_header_);
-  data_page_header_.num_values = num_rows;
-
-  ASSERT_NO_FATAL_FAILURE(WriteDataPageHeader());
-  InitSerializedPageReader(num_rows);
-  std::shared_ptr<Page> current_page = page_reader_->NextPage();
-  ASSERT_NO_FATAL_FAILURE(CheckDataPageHeader(data_page_header_, current_page.get()));
-}
-
-TEST_F(TestPageSerde, TestLargePageHeaders) {
-  int stats_size = 256 * 1024;  // 256 KB
-  AddDummyStats(stats_size, data_page_header_);
-
-  // Any number to verify metadata roundtrip
-  const int32_t num_rows = 4141;
-  data_page_header_.num_values = num_rows;
-
-  int max_header_size = 512 * 1024;  // 512 KB
-  ASSERT_NO_FATAL_FAILURE(WriteDataPageHeader(max_header_size));
-  ASSERT_GE(max_header_size, out_stream_->Tell());
-
-  // check header size is between 256 KB to 16 MB
-  ASSERT_LE(stats_size, out_stream_->Tell());
-  ASSERT_GE(kDefaultMaxPageHeaderSize, out_stream_->Tell());
-
-  InitSerializedPageReader(num_rows);
-  std::shared_ptr<Page> current_page = page_reader_->NextPage();
-  ASSERT_NO_FATAL_FAILURE(CheckDataPageHeader(data_page_header_, current_page.get()));
-}
-
-TEST_F(TestPageSerde, TestFailLargePageHeaders) {
-  const int32_t num_rows = 1337;  // dummy value
-
-  int stats_size = 256 * 1024;  // 256 KB
-  AddDummyStats(stats_size, data_page_header_);
-
-  // Serialize the Page header
-  int max_header_size = 512 * 1024;  // 512 KB
-  ASSERT_NO_FATAL_FAILURE(WriteDataPageHeader(max_header_size));
-  ASSERT_GE(max_header_size, out_stream_->Tell());
-
-  int smaller_max_size = 128 * 1024;
-  ASSERT_LE(smaller_max_size, out_stream_->Tell());
-  InitSerializedPageReader(num_rows);
-
-  // Set the max page header size to 128 KB, which is less than the current
-  // header size
-  page_reader_->set_max_page_header_size(smaller_max_size);
-  ASSERT_THROW(page_reader_->NextPage(), ParquetException);
-}
-
-TEST_F(TestPageSerde, Compression) {
-  Compression::type codec_types[5] = {Compression::GZIP, Compression::SNAPPY,
-                                      Compression::BROTLI, Compression::LZ4,
-                                      Compression::ZSTD};
-
-  const int32_t num_rows = 32;  // dummy value
-  data_page_header_.num_values = num_rows;
-
-  int num_pages = 10;
-
-  std::vector<std::vector<uint8_t>> faux_data;
-  faux_data.resize(num_pages);
-  for (int i = 0; i < num_pages; ++i) {
-    // The pages keep getting larger
-    int page_size = (i + 1) * 64;
-    test::random_bytes(page_size, 0, &faux_data[i]);
-  }
-  for (auto codec_type : codec_types) {
-    std::unique_ptr<::arrow::Codec> codec = GetCodecFromArrow(codec_type);
-
-    std::vector<uint8_t> buffer;
-    for (int i = 0; i < num_pages; ++i) {
-      const uint8_t* data = faux_data[i].data();
-      int data_size = static_cast<int>(faux_data[i].size());
-
-      int64_t max_compressed_size = codec->MaxCompressedLen(data_size, data);
-      buffer.resize(max_compressed_size);
-
-      int64_t actual_size;
-      ASSERT_OK(codec->Compress(data_size, data, max_compressed_size, &buffer[0],
-                                &actual_size));
-
-      ASSERT_NO_FATAL_FAILURE(
-          WriteDataPageHeader(1024, data_size, static_cast<int32_t>(actual_size)));
-      out_stream_->Write(buffer.data(), actual_size);
-    }
-
-    InitSerializedPageReader(num_rows * num_pages, codec_type);
-
-    std::shared_ptr<Page> page;
-    const DataPage* data_page;
-    for (int i = 0; i < num_pages; ++i) {
-      int data_size = static_cast<int>(faux_data[i].size());
-      page = page_reader_->NextPage();
-      data_page = static_cast<const DataPage*>(page.get());
-      ASSERT_EQ(data_size, data_page->size());
-      ASSERT_EQ(0, memcmp(faux_data[i].data(), data_page->data(), data_size));
-    }
-
-    ResetStream();
-  }
-}
-
-TEST_F(TestPageSerde, LZONotSupported) {
-  // Must await PARQUET-530
-  int data_size = 1024;
-  std::vector<uint8_t> faux_data(data_size);
-  ASSERT_NO_FATAL_FAILURE(WriteDataPageHeader(1024, data_size, data_size));
-  out_stream_->Write(faux_data.data(), data_size);
-  ASSERT_THROW(InitSerializedPageReader(data_size, Compression::LZO), ParquetException);
-}
-
-// ----------------------------------------------------------------------
-// File structure tests
-
-class TestParquetFileReader : public ::testing::Test {
- public:
-  void AssertInvalidFileThrows(const std::shared_ptr<Buffer>& buffer) {
-    reader_.reset(new ParquetFileReader());
-
-    auto reader = std::make_shared<BufferReader>(buffer);
-    auto wrapper = std::unique_ptr<ArrowInputFile>(new ArrowInputFile(reader));
-
-    ASSERT_THROW(reader_->Open(ParquetFileReader::Contents::Open(std::move(wrapper))),
-                 ParquetException);
-  }
-
- protected:
-  std::unique_ptr<ParquetFileReader> reader_;
-};
-
-TEST_F(TestParquetFileReader, InvalidHeader) {
-  const char* bad_header = "PAR2";
-
-  auto buffer = std::make_shared<Buffer>(reinterpret_cast<const uint8_t*>(bad_header),
-                                         strlen(bad_header));
-  ASSERT_NO_FATAL_FAILURE(AssertInvalidFileThrows(buffer));
-}
-
-TEST_F(TestParquetFileReader, InvalidFooter) {
-  // File is smaller than FOOTER_SIZE
-  const char* bad_file = "PAR1PAR";
-  auto buffer = std::make_shared<Buffer>(reinterpret_cast<const uint8_t*>(bad_file),
-                                         strlen(bad_file));
-  ASSERT_NO_FATAL_FAILURE(AssertInvalidFileThrows(buffer));
-
-  // Magic number incorrect
-  const char* bad_file2 = "PAR1PAR2";
-  buffer = std::make_shared<Buffer>(reinterpret_cast<const uint8_t*>(bad_file2),
-                                    strlen(bad_file2));
-  ASSERT_NO_FATAL_FAILURE(AssertInvalidFileThrows(buffer));
-}
-
-TEST_F(TestParquetFileReader, IncompleteMetadata) {
-  InMemoryOutputStream stream;
-
-  const char* magic = "PAR1";
-
-  stream.Write(reinterpret_cast<const uint8_t*>(magic), strlen(magic));
-  std::vector<uint8_t> bytes(10);
-  stream.Write(bytes.data(), bytes.size());
-  uint32_t metadata_len = 24;
-  stream.Write(reinterpret_cast<const uint8_t*>(&metadata_len), sizeof(uint32_t));
-  stream.Write(reinterpret_cast<const uint8_t*>(magic), strlen(magic));
-
-  auto buffer = stream.GetBuffer();
-  ASSERT_NO_FATAL_FAILURE(AssertInvalidFileThrows(buffer));
-}
-
-}  // namespace parquet
diff --git a/src/parquet/file-serialize-test.cc b/src/parquet/file-serialize-test.cc
deleted file mode 100644
index 750faa2..0000000
--- a/src/parquet/file-serialize-test.cc
+++ /dev/null
@@ -1,310 +0,0 @@
-// 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.
-
-#include <gtest/gtest.h>
-
-#include "parquet/column_reader.h"
-#include "parquet/column_writer.h"
-#include "parquet/file_reader.h"
-#include "parquet/file_writer.h"
-#include "parquet/test-specialization.h"
-#include "parquet/test-util.h"
-#include "parquet/types.h"
-#include "parquet/util/memory.h"
-
-namespace parquet {
-
-using schema::GroupNode;
-using schema::NodePtr;
-using schema::PrimitiveNode;
-
-namespace test {
-
-template <typename TestType>
-class TestSerialize : public PrimitiveTypedTest<TestType> {
- public:
-  typedef typename TestType::c_type T;
-
-  void SetUp() {
-    num_columns_ = 4;
-    num_rowgroups_ = 4;
-    rows_per_rowgroup_ = 50;
-    rows_per_batch_ = 10;
-    this->SetUpSchema(Repetition::OPTIONAL, num_columns_);
-  }
-
- protected:
-  int num_columns_;
-  int num_rowgroups_;
-  int rows_per_rowgroup_;
-  int rows_per_batch_;
-
-  void FileSerializeTest(Compression::type codec_type) {
-    std::shared_ptr<InMemoryOutputStream> sink(new InMemoryOutputStream());
-    auto gnode = std::static_pointer_cast<GroupNode>(this->node_);
-
-    WriterProperties::Builder prop_builder;
-
-    for (int i = 0; i < num_columns_; ++i) {
-      prop_builder.compression(this->schema_.Column(i)->name(), codec_type);
-    }
-    std::shared_ptr<WriterProperties> writer_properties = prop_builder.build();
-
-    auto file_writer = ParquetFileWriter::Open(sink, gnode, writer_properties);
-    this->GenerateData(rows_per_rowgroup_);
-    for (int rg = 0; rg < num_rowgroups_ / 2; ++rg) {
-      RowGroupWriter* row_group_writer;
-      row_group_writer = file_writer->AppendRowGroup();
-      for (int col = 0; col < num_columns_; ++col) {
-        auto column_writer =
-            static_cast<TypedColumnWriter<TestType>*>(row_group_writer->NextColumn());
-        column_writer->WriteBatch(rows_per_rowgroup_, this->def_levels_.data(), nullptr,
-                                  this->values_ptr_);
-        column_writer->Close();
-        // Ensure column() API which is specific to BufferedRowGroup cannot be called
-        ASSERT_THROW(row_group_writer->column(col), ParquetException);
-      }
-
-      row_group_writer->Close();
-    }
-    // Write half BufferedRowGroups
-    for (int rg = 0; rg < num_rowgroups_ / 2; ++rg) {
-      RowGroupWriter* row_group_writer;
-      row_group_writer = file_writer->AppendBufferedRowGroup();
-      for (int batch = 0; batch < (rows_per_rowgroup_ / rows_per_batch_); ++batch) {
-        for (int col = 0; col < num_columns_; ++col) {
-          auto column_writer =
-              static_cast<TypedColumnWriter<TestType>*>(row_group_writer->column(col));
-          column_writer->WriteBatch(
-              rows_per_batch_, this->def_levels_.data() + (batch * rows_per_batch_),
-              nullptr, this->values_ptr_ + (batch * rows_per_batch_));
-          // Ensure NextColumn() API which is specific to RowGroup cannot be called
-          ASSERT_THROW(row_group_writer->NextColumn(), ParquetException);
-        }
-      }
-      for (int col = 0; col < num_columns_; ++col) {
-        auto column_writer =
-            static_cast<TypedColumnWriter<TestType>*>(row_group_writer->column(col));
-        column_writer->Close();
-      }
-      row_group_writer->Close();
-    }
-    file_writer->Close();
-
-    auto buffer = sink->GetBuffer();
-    int num_rows_ = num_rowgroups_ * rows_per_rowgroup_;
-
-    auto source = std::make_shared<::arrow::io::BufferReader>(buffer);
-    auto file_reader = ParquetFileReader::Open(source);
-    ASSERT_EQ(num_columns_, file_reader->metadata()->num_columns());
-    ASSERT_EQ(num_rowgroups_, file_reader->metadata()->num_row_groups());
-    ASSERT_EQ(num_rows_, file_reader->metadata()->num_rows());
-
-    for (int rg = 0; rg < num_rowgroups_; ++rg) {
-      auto rg_reader = file_reader->RowGroup(rg);
-      ASSERT_EQ(num_columns_, rg_reader->metadata()->num_columns());
-      ASSERT_EQ(rows_per_rowgroup_, rg_reader->metadata()->num_rows());
-      // Check that the specified compression was actually used.
-      ASSERT_EQ(codec_type, rg_reader->metadata()->ColumnChunk(0)->compression());
-
-      int64_t values_read;
-
-      for (int i = 0; i < num_columns_; ++i) {
-        ASSERT_FALSE(rg_reader->metadata()->ColumnChunk(i)->has_index_page());
-        std::vector<int16_t> def_levels_out(rows_per_rowgroup_);
-        std::vector<int16_t> rep_levels_out(rows_per_rowgroup_);
-        auto col_reader =
-            std::static_pointer_cast<TypedColumnReader<TestType>>(rg_reader->Column(i));
-        this->SetupValuesOut(rows_per_rowgroup_);
-        col_reader->ReadBatch(rows_per_rowgroup_, def_levels_out.data(),
-                              rep_levels_out.data(), this->values_out_ptr_, &values_read);
-        this->SyncValuesOut();
-        ASSERT_EQ(rows_per_rowgroup_, values_read);
-        ASSERT_EQ(this->values_, this->values_out_);
-        ASSERT_EQ(this->def_levels_, def_levels_out);
-      }
-    }
-  }
-
-  void UnequalNumRows(int64_t max_rows, const std::vector<int64_t> rows_per_column) {
-    std::shared_ptr<InMemoryOutputStream> sink(new InMemoryOutputStream());
-    auto gnode = std::static_pointer_cast<GroupNode>(this->node_);
-
-    std::shared_ptr<WriterProperties> props = WriterProperties::Builder().build();
-
-    auto file_writer = ParquetFileWriter::Open(sink, gnode, props);
-
-    RowGroupWriter* row_group_writer;
-    row_group_writer = file_writer->AppendRowGroup();
-
-    this->GenerateData(max_rows);
-    for (int col = 0; col < num_columns_; ++col) {
-      auto column_writer =
-          static_cast<TypedColumnWriter<TestType>*>(row_group_writer->NextColumn());
-      column_writer->WriteBatch(rows_per_column[col], this->def_levels_.data(), nullptr,
-                                this->values_ptr_);
-      column_writer->Close();
-    }
-    row_group_writer->Close();
-    file_writer->Close();
-  }
-
-  void UnequalNumRowsBuffered(int64_t max_rows,
-                              const std::vector<int64_t> rows_per_column) {
-    std::shared_ptr<InMemoryOutputStream> sink(new InMemoryOutputStream());
-    auto gnode = std::static_pointer_cast<GroupNode>(this->node_);
-
-    std::shared_ptr<WriterProperties> props = WriterProperties::Builder().build();
-
-    auto file_writer = ParquetFileWriter::Open(sink, gnode, props);
-
-    RowGroupWriter* row_group_writer;
-    row_group_writer = file_writer->AppendBufferedRowGroup();
-
-    this->GenerateData(max_rows);
-    for (int col = 0; col < num_columns_; ++col) {
-      auto column_writer =
-          static_cast<TypedColumnWriter<TestType>*>(row_group_writer->column(col));
-      column_writer->WriteBatch(rows_per_column[col], this->def_levels_.data(), nullptr,
-                                this->values_ptr_);
-      column_writer->Close();
-    }
-    row_group_writer->Close();
-    file_writer->Close();
-  }
-
-  void RepeatedUnequalRows() {
-    // Optional and repeated, so definition and repetition levels
-    this->SetUpSchema(Repetition::REPEATED);
-
-    const int kNumRows = 100;
-    this->GenerateData(kNumRows);
-
-    std::shared_ptr<InMemoryOutputStream> sink(new InMemoryOutputStream());
-    auto gnode = std::static_pointer_cast<GroupNode>(this->node_);
-    std::shared_ptr<WriterProperties> props = WriterProperties::Builder().build();
-    auto file_writer = ParquetFileWriter::Open(sink, gnode, props);
-
-    RowGroupWriter* row_group_writer;
-    row_group_writer = file_writer->AppendRowGroup();
-
-    this->GenerateData(kNumRows);
-
-    std::vector<int16_t> definition_levels(kNumRows, 1);
-    std::vector<int16_t> repetition_levels(kNumRows, 0);
-
-    {
-      auto column_writer =
-          static_cast<TypedColumnWriter<TestType>*>(row_group_writer->NextColumn());
-      column_writer->WriteBatch(kNumRows, definition_levels.data(),
-                                repetition_levels.data(), this->values_ptr_);
-      column_writer->Close();
-    }
-
-    definition_levels[1] = 0;
-    repetition_levels[3] = 1;
-
-    {
-      auto column_writer =
-          static_cast<TypedColumnWriter<TestType>*>(row_group_writer->NextColumn());
-      column_writer->WriteBatch(kNumRows, definition_levels.data(),
-                                repetition_levels.data(), this->values_ptr_);
-      column_writer->Close();
-    }
-  }
-
-  void ZeroRowsRowGroup() {
-    std::shared_ptr<InMemoryOutputStream> sink(new InMemoryOutputStream());
-    auto gnode = std::static_pointer_cast<GroupNode>(this->node_);
-
-    std::shared_ptr<WriterProperties> props = WriterProperties::Builder().build();
-
-    auto file_writer = ParquetFileWriter::Open(sink, gnode, props);
-
-    RowGroupWriter* row_group_writer;
-
-    row_group_writer = file_writer->AppendRowGroup();
-    for (int col = 0; col < num_columns_; ++col) {
-      auto column_writer =
-          static_cast<TypedColumnWriter<TestType>*>(row_group_writer->NextColumn());
-      column_writer->Close();
-    }
-    row_group_writer->Close();
-
-    row_group_writer = file_writer->AppendBufferedRowGroup();
-    for (int col = 0; col < num_columns_; ++col) {
-      auto column_writer =
-          static_cast<TypedColumnWriter<TestType>*>(row_group_writer->column(col));
-      column_writer->Close();
-    }
-    row_group_writer->Close();
-
-    file_writer->Close();
-  }
-};
-
-typedef ::testing::Types<Int32Type, Int64Type, Int96Type, FloatType, DoubleType,
-                         BooleanType, ByteArrayType, FLBAType>
-    TestTypes;
-
-TYPED_TEST_CASE(TestSerialize, TestTypes);
-
-TYPED_TEST(TestSerialize, SmallFileUncompressed) {
-  ASSERT_NO_FATAL_FAILURE(this->FileSerializeTest(Compression::UNCOMPRESSED));
-}
-
-TYPED_TEST(TestSerialize, TooFewRows) {
-  std::vector<int64_t> num_rows = {100, 100, 100, 99};
-  ASSERT_THROW(this->UnequalNumRows(100, num_rows), ParquetException);
-  ASSERT_THROW(this->UnequalNumRowsBuffered(100, num_rows), ParquetException);
-}
-
-TYPED_TEST(TestSerialize, TooManyRows) {
-  std::vector<int64_t> num_rows = {100, 100, 100, 101};
-  ASSERT_THROW(this->UnequalNumRows(101, num_rows), ParquetException);
-  ASSERT_THROW(this->UnequalNumRowsBuffered(101, num_rows), ParquetException);
-}
-
-TYPED_TEST(TestSerialize, ZeroRows) { ASSERT_NO_THROW(this->ZeroRowsRowGroup()); }
-
-TYPED_TEST(TestSerialize, RepeatedTooFewRows) {
-  ASSERT_THROW(this->RepeatedUnequalRows(), ParquetException);
-}
-
-TYPED_TEST(TestSerialize, SmallFileSnappy) {
-  ASSERT_NO_FATAL_FAILURE(this->FileSerializeTest(Compression::SNAPPY));
-}
-
-TYPED_TEST(TestSerialize, SmallFileBrotli) {
-  ASSERT_NO_FATAL_FAILURE(this->FileSerializeTest(Compression::BROTLI));
-}
-
-TYPED_TEST(TestSerialize, SmallFileGzip) {
-  ASSERT_NO_FATAL_FAILURE(this->FileSerializeTest(Compression::GZIP));
-}
-
-TYPED_TEST(TestSerialize, SmallFileLz4) {
-  ASSERT_NO_FATAL_FAILURE(this->FileSerializeTest(Compression::LZ4));
-}
-
-TYPED_TEST(TestSerialize, SmallFileZstd) {
-  ASSERT_NO_FATAL_FAILURE(this->FileSerializeTest(Compression::ZSTD));
-}
-
-}  // namespace test
-
-}  // namespace parquet
diff --git a/src/parquet/file_reader.cc b/src/parquet/file_reader.cc
deleted file mode 100644
index c5a0f34..0000000
--- a/src/parquet/file_reader.cc
+++ /dev/null
@@ -1,376 +0,0 @@
-// 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.
-
-#include "parquet/file_reader.h"
-
-#include <algorithm>
-#include <cstdint>
-#include <cstdio>
-#include <memory>
-#include <sstream>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "arrow/io/file.h"
-
-#include "parquet/column_page.h"
-#include "parquet/column_reader.h"
-#include "parquet/column_scanner.h"
-#include "parquet/exception.h"
-#include "parquet/metadata.h"
-#include "parquet/parquet_types.h"
-#include "parquet/properties.h"
-#include "parquet/types.h"
-#include "parquet/util/logging.h"
-#include "parquet/util/memory.h"
-
-using std::string;
-
-namespace arrow {
-
-class Codec;
-
-}  // namespace arrow
-
-namespace parquet {
-
-// PARQUET-978: Minimize footer reads by reading 64 KB from the end of the file
-static constexpr int64_t DEFAULT_FOOTER_READ_SIZE = 64 * 1024;
-static constexpr uint32_t FOOTER_SIZE = 8;
-static constexpr uint8_t PARQUET_MAGIC[4] = {'P', 'A', 'R', '1'};
-
-// For PARQUET-816
-static constexpr int64_t kMaxDictHeaderSize = 100;
-
-// ----------------------------------------------------------------------
-// RowGroupReader public API
-
-RowGroupReader::RowGroupReader(std::unique_ptr<Contents> contents)
-    : contents_(std::move(contents)) {}
-
-std::shared_ptr<ColumnReader> RowGroupReader::Column(int i) {
-  DCHECK(i < metadata()->num_columns())
-      << "The RowGroup only has " << metadata()->num_columns()
-      << "columns, requested column: " << i;
-  const ColumnDescriptor* descr = metadata()->schema()->Column(i);
-
-  std::unique_ptr<PageReader> page_reader = contents_->GetColumnPageReader(i);
-  return ColumnReader::Make(
-      descr, std::move(page_reader),
-      const_cast<ReaderProperties*>(contents_->properties())->memory_pool());
-}
-
-std::unique_ptr<PageReader> RowGroupReader::GetColumnPageReader(int i) {
-  DCHECK(i < metadata()->num_columns())
-      << "The RowGroup only has " << metadata()->num_columns()
-      << "columns, requested column: " << i;
-  return contents_->GetColumnPageReader(i);
-}
-
-// Returns the rowgroup metadata
-const RowGroupMetaData* RowGroupReader::metadata() const { return contents_->metadata(); }
-
-// RowGroupReader::Contents implementation for the Parquet file specification
-class SerializedRowGroup : public RowGroupReader::Contents {
- public:
-  SerializedRowGroup(RandomAccessSource* source, FileMetaData* file_metadata,
-                     int row_group_number, const ReaderProperties& props)
-      : source_(source), file_metadata_(file_metadata), properties_(props) {
-    row_group_metadata_ = file_metadata->RowGroup(row_group_number);
-  }
-
-  const RowGroupMetaData* metadata() const override { return row_group_metadata_.get(); }
-
-  const ReaderProperties* properties() const override { return &properties_; }
-
-  std::unique_ptr<PageReader> GetColumnPageReader(int i) override {
-    // Read column chunk from the file
-    auto col = row_group_metadata_->ColumnChunk(i);
-
-    int64_t col_start = col->data_page_offset();
-    if (col->has_dictionary_page() && col_start > col->dictionary_page_offset()) {
-      col_start = col->dictionary_page_offset();
-    }
-
-    int64_t col_length = col->total_compressed_size();
-    std::unique_ptr<InputStream> stream;
-
-    // PARQUET-816 workaround for old files created by older parquet-mr
-    const ApplicationVersion& version = file_metadata_->writer_version();
-    if (version.VersionLt(ApplicationVersion::PARQUET_816_FIXED_VERSION())) {
-      // The Parquet MR writer had a bug in 1.2.8 and below where it didn't include the
-      // dictionary page header size in total_compressed_size and total_uncompressed_size
-      // (see IMPALA-694). We add padding to compensate.
-      int64_t bytes_remaining = source_->Size() - (col_start + col_length);
-      int64_t padding = std::min<int64_t>(kMaxDictHeaderSize, bytes_remaining);
-      col_length += padding;
-    }
-
-    stream = properties_.GetStream(source_, col_start, col_length);
-
-    return PageReader::Open(std::move(stream), col->num_values(), col->compression(),
-                            properties_.memory_pool());
-  }
-
- private:
-  RandomAccessSource* source_;
-  FileMetaData* file_metadata_;
-  std::unique_ptr<RowGroupMetaData> row_group_metadata_;
-  ReaderProperties properties_;
-};
-
-// ----------------------------------------------------------------------
-// SerializedFile: An implementation of ParquetFileReader::Contents that deals
-// with the Parquet file structure, Thrift deserialization, and other internal
-// matters
-
-// This class takes ownership of the provided data source
-class SerializedFile : public ParquetFileReader::Contents {
- public:
-  SerializedFile(std::unique_ptr<RandomAccessSource> source,
-                 const ReaderProperties& props = default_reader_properties())
-      : source_(std::move(source)), properties_(props) {}
-
-  ~SerializedFile() override {
-    try {
-      Close();
-    } catch (...) {
-    }
-  }
-
-  void Close() override { source_->Close(); }
-
-  std::shared_ptr<RowGroupReader> GetRowGroup(int i) override {
-    std::unique_ptr<SerializedRowGroup> contents(
-        new SerializedRowGroup(source_.get(), file_metadata_.get(), i, properties_));
-    return std::make_shared<RowGroupReader>(std::move(contents));
-  }
-
-  std::shared_ptr<FileMetaData> metadata() const override { return file_metadata_; }
-
-  void set_metadata(const std::shared_ptr<FileMetaData>& metadata) {
-    file_metadata_ = metadata;
-  }
-
-  void ParseMetaData() {
-    int64_t file_size = source_->Size();
-
-    if (file_size < FOOTER_SIZE) {
-      throw ParquetException("Corrupted file, smaller than file footer");
-    }
-
-    uint8_t footer_buffer[DEFAULT_FOOTER_READ_SIZE];
-    int64_t footer_read_size = std::min(file_size, DEFAULT_FOOTER_READ_SIZE);
-    int64_t bytes_read =
-        source_->ReadAt(file_size - footer_read_size, footer_read_size, footer_buffer);
-
-    // Check if all bytes are read. Check if last 4 bytes read have the magic bits
-    if (bytes_read != footer_read_size ||
-        memcmp(footer_buffer + footer_read_size - 4, PARQUET_MAGIC, 4) != 0) {
-      throw ParquetException("Invalid parquet file. Corrupt footer.");
-    }
-
-    uint32_t metadata_len =
-        *reinterpret_cast<uint32_t*>(footer_buffer + footer_read_size - FOOTER_SIZE);
-    int64_t metadata_start = file_size - FOOTER_SIZE - metadata_len;
-    if (FOOTER_SIZE + metadata_len > file_size) {
-      throw ParquetException(
-          "Invalid parquet file. File is less than "
-          "file metadata size.");
-    }
-
-    std::shared_ptr<ResizableBuffer> metadata_buffer =
-        AllocateBuffer(properties_.memory_pool(), metadata_len);
-
-    // Check if the footer_buffer contains the entire metadata
-    if (footer_read_size >= (metadata_len + FOOTER_SIZE)) {
-      memcpy(metadata_buffer->mutable_data(),
-             footer_buffer + (footer_read_size - metadata_len - FOOTER_SIZE),
-             metadata_len);
-    } else {
-      bytes_read =
-          source_->ReadAt(metadata_start, metadata_len, metadata_buffer->mutable_data());
-      if (bytes_read != metadata_len) {
-        throw ParquetException("Invalid parquet file. Could not read metadata bytes.");
-      }
-    }
-
-    file_metadata_ = FileMetaData::Make(metadata_buffer->data(), &metadata_len);
-  }
-
- private:
-  std::unique_ptr<RandomAccessSource> source_;
-  std::shared_ptr<FileMetaData> file_metadata_;
-  ReaderProperties properties_;
-};
-
-// ----------------------------------------------------------------------
-// ParquetFileReader public API
-
-ParquetFileReader::ParquetFileReader() {}
-
-ParquetFileReader::~ParquetFileReader() {
-  try {
-    Close();
-  } catch (...) {
-  }
-}
-
-// Open the file. If no metadata is passed, it is parsed from the footer of
-// the file
-std::unique_ptr<ParquetFileReader::Contents> ParquetFileReader::Contents::Open(
-    std::unique_ptr<RandomAccessSource> source, const ReaderProperties& props,
-    const std::shared_ptr<FileMetaData>& metadata) {
-  std::unique_ptr<ParquetFileReader::Contents> result(
-      new SerializedFile(std::move(source), props));
-
-  // Access private methods here, but otherwise unavailable
-  SerializedFile* file = static_cast<SerializedFile*>(result.get());
-
-  if (metadata == nullptr) {
-    // Validates magic bytes, parses metadata, and initializes the SchemaDescriptor
-    file->ParseMetaData();
-  } else {
-    file->set_metadata(metadata);
-  }
-
-  return result;
-}
-
-std::unique_ptr<ParquetFileReader> ParquetFileReader::Open(
-    const std::shared_ptr<::arrow::io::ReadableFileInterface>& source,
-    const ReaderProperties& props, const std::shared_ptr<FileMetaData>& metadata) {
-  std::unique_ptr<RandomAccessSource> io_wrapper(new ArrowInputFile(source));
-  return Open(std::move(io_wrapper), props, metadata);
-}
-
-std::unique_ptr<ParquetFileReader> ParquetFileReader::Open(
-    std::unique_ptr<RandomAccessSource> source, const ReaderProperties& props,
-    const std::shared_ptr<FileMetaData>& metadata) {
-  auto contents = SerializedFile::Open(std::move(source), props, metadata);
-  std::unique_ptr<ParquetFileReader> result(new ParquetFileReader());
-  result->Open(std::move(contents));
-  return result;
-}
-
-std::unique_ptr<ParquetFileReader> ParquetFileReader::OpenFile(
-    const std::string& path, bool memory_map, const ReaderProperties& props,
-    const std::shared_ptr<FileMetaData>& metadata) {
-  std::shared_ptr<::arrow::io::ReadableFileInterface> source;
-  if (memory_map) {
-    std::shared_ptr<::arrow::io::MemoryMappedFile> handle;
-    PARQUET_THROW_NOT_OK(
-        ::arrow::io::MemoryMappedFile::Open(path, ::arrow::io::FileMode::READ, &handle));
-    source = handle;
-  } else {
-    std::shared_ptr<::arrow::io::ReadableFile> handle;
-    PARQUET_THROW_NOT_OK(
-        ::arrow::io::ReadableFile::Open(path, props.memory_pool(), &handle));
-    source = handle;
-  }
-
-  return Open(source, props, metadata);
-}
-
-void ParquetFileReader::Open(std::unique_ptr<ParquetFileReader::Contents> contents) {
-  contents_ = std::move(contents);
-}
-
-void ParquetFileReader::Close() {
-  if (contents_) {
-    contents_->Close();
-  }
-}
-
-std::shared_ptr<FileMetaData> ParquetFileReader::metadata() const {
-  return contents_->metadata();
-}
-
-std::shared_ptr<RowGroupReader> ParquetFileReader::RowGroup(int i) {
-  DCHECK(i < metadata()->num_row_groups())
-      << "The file only has " << metadata()->num_row_groups()
-      << "row groups, requested reader for: " << i;
-  return contents_->GetRowGroup(i);
-}
-
-// ----------------------------------------------------------------------
-// File metadata helpers
-
-std::shared_ptr<FileMetaData> ReadMetaData(
-    const std::shared_ptr<::arrow::io::ReadableFileInterface>& source) {
-  return ParquetFileReader::Open(source)->metadata();
-}
-
-// ----------------------------------------------------------------------
-// File scanner for performance testing
-
-int64_t ScanFileContents(std::vector<int> columns, const int32_t column_batch_size,
-                         ParquetFileReader* reader) {
-  std::vector<int16_t> rep_levels(column_batch_size);
-  std::vector<int16_t> def_levels(column_batch_size);
-
-  int num_columns = static_cast<int>(columns.size());
-
-  // columns are not specified explicitly. Add all columns
-  if (columns.size() == 0) {
-    num_columns = reader->metadata()->num_columns();
-    columns.resize(num_columns);
-    for (int i = 0; i < num_columns; i++) {
-      columns[i] = i;
-    }
-  }
-
-  std::vector<int64_t> total_rows(num_columns, 0);
-
-  for (int r = 0; r < reader->metadata()->num_row_groups(); ++r) {
-    auto group_reader = reader->RowGroup(r);
-    int col = 0;
-    for (auto i : columns) {
-      std::shared_ptr<ColumnReader> col_reader = group_reader->Column(i);
-      size_t value_byte_size = GetTypeByteSize(col_reader->descr()->physical_type());
-      std::vector<uint8_t> values(column_batch_size * value_byte_size);
-
-      int64_t values_read = 0;
-      while (col_reader->HasNext()) {
-        int64_t levels_read =
-            ScanAllValues(column_batch_size, def_levels.data(), rep_levels.data(),
-                          values.data(), &values_read, col_reader.get());
-        if (col_reader->descr()->max_repetition_level() > 0) {
-          for (int64_t i = 0; i < levels_read; i++) {
-            if (rep_levels[i] == 0) {
-              total_rows[col]++;
-            }
-          }
-        } else {
-          total_rows[col] += levels_read;
-        }
-      }
-      col++;
-    }
-  }
-
-  for (int i = 1; i < num_columns; ++i) {
-    if (total_rows[0] != total_rows[i]) {
-      throw ParquetException("Parquet error: Total rows among columns do not match");
-    }
-  }
-
-  return total_rows[0];
-}
-
-}  // namespace parquet
diff --git a/src/parquet/file_reader.h b/src/parquet/file_reader.h
deleted file mode 100644
index f751e9b..0000000
--- a/src/parquet/file_reader.h
+++ /dev/null
@@ -1,142 +0,0 @@
-// 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.
-
-#ifndef PARQUET_FILE_READER_H
-#define PARQUET_FILE_READER_H
-
-#include <cstdint>
-#include <iosfwd>
-#include <list>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "parquet/column_reader.h"
-#include "parquet/metadata.h"
-#include "parquet/properties.h"
-#include "parquet/schema.h"
-#include "parquet/statistics.h"
-#include "parquet/util/memory.h"
-#include "parquet/util/visibility.h"
-
-namespace parquet {
-
-class ColumnReader;
-
-class PARQUET_EXPORT RowGroupReader {
- public:
-  // Forward declare a virtual class 'Contents' to aid dependency injection and more
-  // easily create test fixtures
-  // An implementation of the Contents class is defined in the .cc file
-  struct Contents {
-    virtual ~Contents() {}
-    virtual std::unique_ptr<PageReader> GetColumnPageReader(int i) = 0;
-    virtual const RowGroupMetaData* metadata() const = 0;
-    virtual const ReaderProperties* properties() const = 0;
-  };
-
-  explicit RowGroupReader(std::unique_ptr<Contents> contents);
-
-  // Returns the rowgroup metadata
-  const RowGroupMetaData* metadata() const;
-
-  // Construct a ColumnReader for the indicated row group-relative
-  // column. Ownership is shared with the RowGroupReader.
-  std::shared_ptr<ColumnReader> Column(int i);
-
-  std::unique_ptr<PageReader> GetColumnPageReader(int i);
-
- private:
-  // Holds a pointer to an instance of Contents implementation
-  std::unique_ptr<Contents> contents_;
-};
-
-class PARQUET_EXPORT ParquetFileReader {
- public:
-  // Forward declare a virtual class 'Contents' to aid dependency injection and more
-  // easily create test fixtures
-  // An implementation of the Contents class is defined in the .cc file
-  struct Contents {
-    static std::unique_ptr<Contents> Open(
-        std::unique_ptr<RandomAccessSource> source,
-        const ReaderProperties& props = default_reader_properties(),
-        const std::shared_ptr<FileMetaData>& metadata = nullptr);
-
-    virtual ~Contents() {}
-    // Perform any cleanup associated with the file contents
-    virtual void Close() = 0;
-    virtual std::shared_ptr<RowGroupReader> GetRowGroup(int i) = 0;
-    virtual std::shared_ptr<FileMetaData> metadata() const = 0;
-  };
-
-  ParquetFileReader();
-  ~ParquetFileReader();
-
-  // Create a reader from some implementation of parquet-cpp's generic file
-  // input interface
-  //
-  // If you cannot provide exclusive access to your file resource, create a
-  // subclass of RandomAccessSource that wraps the shared resource
-  static std::unique_ptr<ParquetFileReader> Open(
-      std::unique_ptr<RandomAccessSource> source,
-      const ReaderProperties& props = default_reader_properties(),
-      const std::shared_ptr<FileMetaData>& metadata = nullptr);
-
-  // Create a file reader instance from an Arrow file object. Thread-safety is
-  // the responsibility of the file implementation
-  static std::unique_ptr<ParquetFileReader> Open(
-      const std::shared_ptr<::arrow::io::ReadableFileInterface>& source,
-      const ReaderProperties& props = default_reader_properties(),
-      const std::shared_ptr<FileMetaData>& metadata = nullptr);
-
-  // API Convenience to open a serialized Parquet file on disk, using Arrow IO
-  // interfaces.
-  static std::unique_ptr<ParquetFileReader> OpenFile(
-      const std::string& path, bool memory_map = true,
-      const ReaderProperties& props = default_reader_properties(),
-      const std::shared_ptr<FileMetaData>& metadata = nullptr);
-
-  void Open(std::unique_ptr<Contents> contents);
-  void Close();
-
-  // The RowGroupReader is owned by the FileReader
-  std::shared_ptr<RowGroupReader> RowGroup(int i);
-
-  // Returns the file metadata. Only one instance is ever created
-  std::shared_ptr<FileMetaData> metadata() const;
-
- private:
-  // Holds a pointer to an instance of Contents implementation
-  std::unique_ptr<Contents> contents_;
-};
-
-// Read only Parquet file metadata
-std::shared_ptr<FileMetaData> PARQUET_EXPORT
-ReadMetaData(const std::shared_ptr<::arrow::io::ReadableFileInterface>& source);
-
-/// \brief Scan all values in file. Useful for performance testing
-/// \param[in] columns the column numbers to scan. If empty scans all
-/// \param[in] column_batch_size number of values to read at a time when scanning column
-/// \param[in] reader a ParquetFileReader instance
-/// \return number of semantic rows in file
-PARQUET_EXPORT
-int64_t ScanFileContents(std::vector<int> columns, const int32_t column_batch_size,
-                         ParquetFileReader* reader);
-
-}  // namespace parquet
-
-#endif  // PARQUET_FILE_READER_H
diff --git a/src/parquet/file_writer.cc b/src/parquet/file_writer.cc
deleted file mode 100644
index 30673c5..0000000
--- a/src/parquet/file_writer.cc
+++ /dev/null
@@ -1,419 +0,0 @@
-// 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.
-
-#include "parquet/file_writer.h"
-
-#include <vector>
-
-#include "parquet/column_writer.h"
-#include "parquet/schema-internal.h"
-#include "parquet/schema.h"
-#include "parquet/thrift.h"
-#include "parquet/util/memory.h"
-
-using arrow::MemoryPool;
-
-using parquet::schema::GroupNode;
-using parquet::schema::SchemaFlattener;
-
-namespace parquet {
-
-// FIXME: copied from reader-internal.cc
-static constexpr uint8_t PARQUET_MAGIC[4] = {'P', 'A', 'R', '1'};
-
-// ----------------------------------------------------------------------
-// RowGroupWriter public API
-
-RowGroupWriter::RowGroupWriter(std::unique_ptr<Contents> contents)
-    : contents_(std::move(contents)) {}
-
-void RowGroupWriter::Close() {
-  if (contents_) {
-    contents_->Close();
-  }
-}
-
-ColumnWriter* RowGroupWriter::NextColumn() { return contents_->NextColumn(); }
-
-ColumnWriter* RowGroupWriter::column(int i) { return contents_->column(i); }
-
-int64_t RowGroupWriter::total_compressed_bytes() const {
-  return contents_->total_compressed_bytes();
-}
-
-int64_t RowGroupWriter::total_bytes_written() const {
-  return contents_->total_bytes_written();
-}
-
-int RowGroupWriter::current_column() { return contents_->current_column(); }
-
-int RowGroupWriter::num_columns() const { return contents_->num_columns(); }
-
-int64_t RowGroupWriter::num_rows() const { return contents_->num_rows(); }
-
-inline void ThrowRowsMisMatchError(int col, int64_t prev, int64_t curr) {
-  std::stringstream ss;
-  ss << "Column " << col << " had " << curr << " while previous column had " << prev;
-  throw ParquetException(ss.str());
-}
-
-// ----------------------------------------------------------------------
-// RowGroupSerializer
-
-// RowGroupWriter::Contents implementation for the Parquet file specification
-class RowGroupSerializer : public RowGroupWriter::Contents {
- public:
-  RowGroupSerializer(OutputStream* sink, RowGroupMetaDataBuilder* metadata,
-                     const WriterProperties* properties, bool buffered_row_group = false)
-      : sink_(sink),
-        metadata_(metadata),
-        properties_(properties),
-        total_bytes_written_(0),
-        closed_(false),
-        current_column_index_(0),
-        num_rows_(0),
-        buffered_row_group_(buffered_row_group) {
-    if (buffered_row_group) {
-      InitColumns();
-    } else {
-      column_writers_.push_back(nullptr);
-    }
-  }
-
-  int num_columns() const override { return metadata_->num_columns(); }
-
-  int64_t num_rows() const override {
-    CheckRowsWritten();
-    // CheckRowsWritten ensures num_rows_ is set correctly
-    return num_rows_;
-  }
-
-  ColumnWriter* NextColumn() override {
-    if (buffered_row_group_) {
-      throw ParquetException(
-          "NextColumn() is not supported when a RowGroup is written by size");
-    }
-
-    if (column_writers_[0]) {
-      CheckRowsWritten();
-    }
-
-    // Throws an error if more columns are being written
-    auto col_meta = metadata_->NextColumnChunk();
-
-    if (column_writers_[0]) {
-      total_bytes_written_ += column_writers_[0]->Close();
-    }
-
-    ++current_column_index_;
-
-    const ColumnDescriptor* column_descr = col_meta->descr();
-    std::unique_ptr<PageWriter> pager =
-        PageWriter::Open(sink_, properties_->compression(column_descr->path()), col_meta,
-                         properties_->memory_pool());
-    column_writers_[0] = ColumnWriter::Make(col_meta, std::move(pager), properties_);
-    return column_writers_[0].get();
-  }
-
-  ColumnWriter* column(int i) override {
-    if (!buffered_row_group_) {
-      throw ParquetException(
-          "column() is only supported when a BufferedRowGroup is being written");
-    }
-
-    if (i >= 0 && i < static_cast<int>(column_writers_.size())) {
-      return column_writers_[i].get();
-    }
-    return nullptr;
-  }
-
-  int current_column() const override { return metadata_->current_column(); }
-
-  int64_t total_compressed_bytes() const override {
-    int64_t total_compressed_bytes = 0;
-    for (size_t i = 0; i < column_writers_.size(); i++) {
-      if (column_writers_[i]) {
-        total_compressed_bytes += column_writers_[i]->total_compressed_bytes();
-      }
-    }
-    return total_compressed_bytes;
-  }
-
-  int64_t total_bytes_written() const override {
-    int64_t total_bytes_written = 0;
-    for (size_t i = 0; i < column_writers_.size(); i++) {
-      if (column_writers_[i]) {
-        total_bytes_written += column_writers_[i]->total_bytes_written();
-      }
-    }
-    return total_bytes_written;
-  }
-
-  void Close() override {
-    if (!closed_) {
-      closed_ = true;
-      CheckRowsWritten();
-
-      for (size_t i = 0; i < column_writers_.size(); i++) {
-        if (column_writers_[i]) {
-          total_bytes_written_ += column_writers_[i]->Close();
-          column_writers_[i].reset();
-        }
-      }
-
-      column_writers_.clear();
-
-      // Ensures all columns have been written
-      metadata_->set_num_rows(num_rows_);
-      metadata_->Finish(total_bytes_written_);
-    }
-  }
-
- private:
-  OutputStream* sink_;
-  mutable RowGroupMetaDataBuilder* metadata_;
-  const WriterProperties* properties_;
-  int64_t total_bytes_written_;
-  bool closed_;
-  int current_column_index_;
-  mutable int64_t num_rows_;
-  bool buffered_row_group_;
-
-  void CheckRowsWritten() const {
-    // verify when only one column is written at a time
-    if (!buffered_row_group_ && column_writers_.size() > 0 && column_writers_[0]) {
-      int64_t current_col_rows = column_writers_[0]->rows_written();
-      if (num_rows_ == 0) {
-        num_rows_ = current_col_rows;
-      } else if (num_rows_ != current_col_rows) {
-        ThrowRowsMisMatchError(current_column_index_, current_col_rows, num_rows_);
-      }
-    } else if (buffered_row_group_ &&
-               column_writers_.size() > 0) {  // when buffered_row_group = true
-      int64_t current_col_rows = column_writers_[0]->rows_written();
-      for (int i = 1; i < static_cast<int>(column_writers_.size()); i++) {
-        int64_t current_col_rows_i = column_writers_[i]->rows_written();
-        if (current_col_rows != current_col_rows_i) {
-          ThrowRowsMisMatchError(i, current_col_rows_i, current_col_rows);
-        }
-      }
-      num_rows_ = current_col_rows;
-    }
-  }
-
-  void InitColumns() {
-    for (int i = 0; i < num_columns(); i++) {
-      auto col_meta = metadata_->NextColumnChunk();
-      const ColumnDescriptor* column_descr = col_meta->descr();
-      std::unique_ptr<PageWriter> pager =
-          PageWriter::Open(sink_, properties_->compression(column_descr->path()),
-                           col_meta, properties_->memory_pool(), buffered_row_group_);
-      column_writers_.push_back(
-          ColumnWriter::Make(col_meta, std::move(pager), properties_));
-    }
-  }
-
-  std::vector<std::shared_ptr<ColumnWriter>> column_writers_;
-};
-
-// ----------------------------------------------------------------------
-// FileSerializer
-
-// An implementation of ParquetFileWriter::Contents that deals with the Parquet
-// file structure, Thrift serialization, and other internal matters
-
-class FileSerializer : public ParquetFileWriter::Contents {
- public:
-  static std::unique_ptr<ParquetFileWriter::Contents> Open(
-      const std::shared_ptr<OutputStream>& sink, const std::shared_ptr<GroupNode>& schema,
-      const std::shared_ptr<WriterProperties>& properties,
-      const std::shared_ptr<const KeyValueMetadata>& key_value_metadata) {
-    std::unique_ptr<ParquetFileWriter::Contents> result(
-        new FileSerializer(sink, schema, properties, key_value_metadata));
-
-    return result;
-  }
-
-  void Close() override {
-    if (is_open_) {
-      if (row_group_writer_) {
-        num_rows_ += row_group_writer_->num_rows();
-        row_group_writer_->Close();
-      }
-      row_group_writer_.reset();
-
-      // Write magic bytes and metadata
-      auto metadata = metadata_->Finish();
-      WriteFileMetaData(*metadata, sink_.get());
-
-      sink_->Close();
-      is_open_ = false;
-    }
-  }
-
-  int num_columns() const override { return schema_.num_columns(); }
-
-  int num_row_groups() const override { return num_row_groups_; }
-
-  int64_t num_rows() const override { return num_rows_; }
-
-  const std::shared_ptr<WriterProperties>& properties() const override {
-    return properties_;
-  }
-
-  RowGroupWriter* AppendRowGroup(bool buffered_row_group) {
-    if (row_group_writer_) {
-      row_group_writer_->Close();
-    }
-    num_row_groups_++;
-    auto rg_metadata = metadata_->AppendRowGroup();
-    std::unique_ptr<RowGroupWriter::Contents> contents(new RowGroupSerializer(
-        sink_.get(), rg_metadata, properties_.get(), buffered_row_group));
-    row_group_writer_.reset(new RowGroupWriter(std::move(contents)));
-    return row_group_writer_.get();
-  }
-
-  RowGroupWriter* AppendRowGroup() override { return AppendRowGroup(false); }
-
-  RowGroupWriter* AppendBufferedRowGroup() override { return AppendRowGroup(true); }
-
-  ~FileSerializer() override {
-    try {
-      Close();
-    } catch (...) {
-    }
-  }
-
- private:
-  FileSerializer(const std::shared_ptr<OutputStream>& sink,
-                 const std::shared_ptr<GroupNode>& schema,
-                 const std::shared_ptr<WriterProperties>& properties,
-                 const std::shared_ptr<const KeyValueMetadata>& key_value_metadata)
-      : ParquetFileWriter::Contents(schema, key_value_metadata),
-        sink_(sink),
-        is_open_(true),
-        properties_(properties),
-        num_row_groups_(0),
-        num_rows_(0),
-        metadata_(FileMetaDataBuilder::Make(&schema_, properties, key_value_metadata)) {
-    StartFile();
-  }
-
-  std::shared_ptr<OutputStream> sink_;
-  bool is_open_;
-  const std::shared_ptr<WriterProperties> properties_;
-  int num_row_groups_;
-  int64_t num_rows_;
-  std::unique_ptr<FileMetaDataBuilder> metadata_;
-  // Only one of the row group writers is active at a time
-  std::unique_ptr<RowGroupWriter> row_group_writer_;
-
-  void StartFile() {
-    // Parquet files always start with PAR1
-    sink_->Write(PARQUET_MAGIC, 4);
-  }
-};
-
-// ----------------------------------------------------------------------
-// ParquetFileWriter public API
-
-ParquetFileWriter::ParquetFileWriter() {}
-
-ParquetFileWriter::~ParquetFileWriter() {
-  try {
-    Close();
-  } catch (...) {
-  }
-}
-
-std::unique_ptr<ParquetFileWriter> ParquetFileWriter::Open(
-    const std::shared_ptr<::arrow::io::OutputStream>& sink,
-    const std::shared_ptr<GroupNode>& schema,
-    const std::shared_ptr<WriterProperties>& properties,
-    const std::shared_ptr<const KeyValueMetadata>& key_value_metadata) {
-  return Open(std::make_shared<ArrowOutputStream>(sink), schema, properties,
-              key_value_metadata);
-}
-
-std::unique_ptr<ParquetFileWriter> ParquetFileWriter::Open(
-    const std::shared_ptr<OutputStream>& sink,
-    const std::shared_ptr<schema::GroupNode>& schema,
-    const std::shared_ptr<WriterProperties>& properties,
-    const std::shared_ptr<const KeyValueMetadata>& key_value_metadata) {
-  auto contents = FileSerializer::Open(sink, schema, properties, key_value_metadata);
-  std::unique_ptr<ParquetFileWriter> result(new ParquetFileWriter());
-  result->Open(std::move(contents));
-  return result;
-}
-
-void WriteFileMetaData(const FileMetaData& file_metadata, OutputStream* sink) {
-  // Write MetaData
-  uint32_t metadata_len = static_cast<uint32_t>(sink->Tell());
-
-  file_metadata.WriteTo(sink);
-  metadata_len = static_cast<uint32_t>(sink->Tell()) - metadata_len;
-
-  // Write Footer
-  sink->Write(reinterpret_cast<uint8_t*>(&metadata_len), 4);
-  sink->Write(PARQUET_MAGIC, 4);
-}
-
-const SchemaDescriptor* ParquetFileWriter::schema() const { return contents_->schema(); }
-
-const ColumnDescriptor* ParquetFileWriter::descr(int i) const {
-  return contents_->schema()->Column(i);
-}
-
-int ParquetFileWriter::num_columns() const { return contents_->num_columns(); }
-
-int64_t ParquetFileWriter::num_rows() const { return contents_->num_rows(); }
-
-int ParquetFileWriter::num_row_groups() const { return contents_->num_row_groups(); }
-
-const std::shared_ptr<const KeyValueMetadata>& ParquetFileWriter::key_value_metadata()
-    const {
-  return contents_->key_value_metadata();
-}
-
-void ParquetFileWriter::Open(std::unique_ptr<ParquetFileWriter::Contents> contents) {
-  contents_ = std::move(contents);
-}
-
-void ParquetFileWriter::Close() {
-  if (contents_) {
-    contents_->Close();
-    contents_.reset();
-  }
-}
-
-RowGroupWriter* ParquetFileWriter::AppendRowGroup() {
-  return contents_->AppendRowGroup();
-}
-
-RowGroupWriter* ParquetFileWriter::AppendBufferedRowGroup() {
-  return contents_->AppendBufferedRowGroup();
-}
-
-RowGroupWriter* ParquetFileWriter::AppendRowGroup(int64_t num_rows) {
-  return AppendRowGroup();
-}
-
-const std::shared_ptr<WriterProperties>& ParquetFileWriter::properties() const {
-  return contents_->properties();
-}
-
-}  // namespace parquet
diff --git a/src/parquet/file_writer.h b/src/parquet/file_writer.h
deleted file mode 100644
index cdfe06c..0000000
--- a/src/parquet/file_writer.h
+++ /dev/null
@@ -1,219 +0,0 @@
-// 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.
-
-#ifndef PARQUET_FILE_WRITER_H
-#define PARQUET_FILE_WRITER_H
-
-#include <cstdint>
-#include <memory>
-
-#include "parquet/metadata.h"
-#include "parquet/properties.h"
-#include "parquet/schema.h"
-#include "parquet/util/memory.h"
-#include "parquet/util/visibility.h"
-
-namespace parquet {
-
-class ColumnWriter;
-class PageWriter;
-class OutputStream;
-
-namespace schema {
-
-class GroupNode;
-
-}  // namespace schema
-
-class PARQUET_EXPORT RowGroupWriter {
- public:
-  // Forward declare a virtual class 'Contents' to aid dependency injection and more
-  // easily create test fixtures
-  // An implementation of the Contents class is defined in the .cc file
-  struct Contents {
-    virtual ~Contents() = default;
-    virtual int num_columns() const = 0;
-    virtual int64_t num_rows() const = 0;
-
-    // to be used only with ParquetFileWriter::AppendRowGroup
-    virtual ColumnWriter* NextColumn() = 0;
-    // to be used only with ParquetFileWriter::AppendBufferedRowGroup
-    virtual ColumnWriter* column(int i) = 0;
-
-    virtual int current_column() const = 0;
-    virtual void Close() = 0;
-
-    // total bytes written by the page writer
-    virtual int64_t total_bytes_written() const = 0;
-    // total bytes still compressed but not written
-    virtual int64_t total_compressed_bytes() const = 0;
-  };
-
-  explicit RowGroupWriter(std::unique_ptr<Contents> contents);
-
-  /// Construct a ColumnWriter for the indicated row group-relative column.
-  ///
-  /// To be used only with ParquetFileWriter::AppendRowGroup
-  /// Ownership is solely within the RowGroupWriter. The ColumnWriter is only
-  /// valid until the next call to NextColumn or Close. As the contents are
-  /// directly written to the sink, once a new column is started, the contents
-  /// of the previous one cannot be modified anymore.
-  ColumnWriter* NextColumn();
-  /// Index of currently written column
-  int current_column();
-  void Close();
-
-  int num_columns() const;
-
-  /// Construct a ColumnWriter for the indicated row group column.
-  ///
-  /// To be used only with ParquetFileWriter::AppendBufferedRowGroup
-  /// Ownership is solely within the RowGroupWriter. The ColumnWriter is
-  /// valid until Close. The contents are buffered in memory and written to sink
-  /// on Close
-  ColumnWriter* column(int i);
-
-  /**
-   * Number of rows that shall be written as part of this RowGroup.
-   */
-  int64_t num_rows() const;
-
-  int64_t total_bytes_written() const;
-  int64_t total_compressed_bytes() const;
-
- private:
-  // Holds a pointer to an instance of Contents implementation
-  std::unique_ptr<Contents> contents_;
-};
-
-PARQUET_EXPORT
-void WriteFileMetaData(const FileMetaData& file_metadata, OutputStream* sink);
-
-class PARQUET_EXPORT ParquetFileWriter {
- public:
-  // Forward declare a virtual class 'Contents' to aid dependency injection and more
-  // easily create test fixtures
-  // An implementation of the Contents class is defined in the .cc file
-  struct Contents {
-    Contents(const std::shared_ptr<::parquet::schema::GroupNode>& schema,
-             const std::shared_ptr<const KeyValueMetadata>& key_value_metadata)
-        : schema_(), key_value_metadata_(key_value_metadata) {
-      schema_.Init(schema);
-    }
-    virtual ~Contents() {}
-    // Perform any cleanup associated with the file contents
-    virtual void Close() = 0;
-
-    /// \note Deprecated since 1.3.0
-    RowGroupWriter* AppendRowGroup(int64_t num_rows);
-
-    virtual RowGroupWriter* AppendRowGroup() = 0;
-    virtual RowGroupWriter* AppendBufferedRowGroup() = 0;
-
-    virtual int64_t num_rows() const = 0;
-    virtual int num_columns() const = 0;
-    virtual int num_row_groups() const = 0;
-
-    virtual const std::shared_ptr<WriterProperties>& properties() const = 0;
-
-    const std::shared_ptr<const KeyValueMetadata>& key_value_metadata() const {
-      return key_value_metadata_;
-    }
-
-    // Return const-pointer to make it clear that this object is not to be copied
-    const SchemaDescriptor* schema() const { return &schema_; }
-
-    SchemaDescriptor schema_;
-
-    /// This should be the only place this is stored. Everything else is a const reference
-    std::shared_ptr<const KeyValueMetadata> key_value_metadata_;
-  };
-
-  ParquetFileWriter();
-  ~ParquetFileWriter();
-
-  static std::unique_ptr<ParquetFileWriter> Open(
-      const std::shared_ptr<::arrow::io::OutputStream>& sink,
-      const std::shared_ptr<schema::GroupNode>& schema,
-      const std::shared_ptr<WriterProperties>& properties = default_writer_properties(),
-      const std::shared_ptr<const KeyValueMetadata>& key_value_metadata = nullptr);
-
-  static std::unique_ptr<ParquetFileWriter> Open(
-      const std::shared_ptr<OutputStream>& sink,
-      const std::shared_ptr<schema::GroupNode>& schema,
-      const std::shared_ptr<WriterProperties>& properties = default_writer_properties(),
-      const std::shared_ptr<const KeyValueMetadata>& key_value_metadata = nullptr);
-
-  void Open(std::unique_ptr<Contents> contents);
-  void Close();
-
-  // Construct a RowGroupWriter for the indicated number of rows.
-  //
-  // Ownership is solely within the ParquetFileWriter. The RowGroupWriter is only valid
-  // until the next call to AppendRowGroup or AppendBufferedRowGroup or Close.
-  // @param num_rows The number of rows that are stored in the new RowGroup
-  //
-  // \deprecated Since 1.3.0
-  RowGroupWriter* AppendRowGroup(int64_t num_rows);
-
-  /// Construct a RowGroupWriter with an arbitrary number of rows.
-  ///
-  /// Ownership is solely within the ParquetFileWriter. The RowGroupWriter is only valid
-  /// until the next call to AppendRowGroup or AppendBufferedRowGroup or Close.
-  RowGroupWriter* AppendRowGroup();
-
-  /// Construct a RowGroupWriter that buffers all the values until the RowGroup is ready.
-  /// Use this if you want to write a RowGroup based on a certain size
-  ///
-  /// Ownership is solely within the ParquetFileWriter. The RowGroupWriter is only valid
-  /// until the next call to AppendRowGroup or AppendBufferedRowGroup or Close.
-  RowGroupWriter* AppendBufferedRowGroup();
-
-  /// Number of columns.
-  ///
-  /// This number is fixed during the lifetime of the writer as it is determined via
-  /// the schema.
-  int num_columns() const;
-
-  /// Number of rows in the yet started RowGroups.
-  ///
-  /// Changes on the addition of a new RowGroup.
-  int64_t num_rows() const;
-
-  /// Number of started RowGroups.
-  int num_row_groups() const;
-
-  /// Configuration passed to the writer, e.g. the used Parquet format version.
-  const std::shared_ptr<WriterProperties>& properties() const;
-
-  /// Returns the file schema descriptor
-  const SchemaDescriptor* schema() const;
-
-  /// Returns a column descriptor in schema
-  const ColumnDescriptor* descr(int i) const;
-
-  /// Returns the file custom metadata
-  const std::shared_ptr<const KeyValueMetadata>& key_value_metadata() const;
-
- private:
-  // Holds a pointer to an instance of Contents implementation
-  std::unique_ptr<Contents> contents_;
-};
-
-}  // namespace parquet
-
-#endif  // PARQUET_FILE_WRITER_H
diff --git a/src/parquet/hasher.h b/src/parquet/hasher.h
deleted file mode 100644
index dc316a0..0000000
--- a/src/parquet/hasher.h
+++ /dev/null
@@ -1,75 +0,0 @@
-// 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.
-
-#ifndef PARQUET_HASHER_H
-#define PARQUET_HASHER_H
-
-#include <cstdint>
-#include "parquet/types.h"
-
-namespace parquet {
-// Abstract class for hash
-class Hasher {
- public:
-  /// Compute hash for 32 bits value by using its plain encoding result.
-  ///
-  /// @param value the value to hash.
-  /// @return hash result.
-  virtual uint64_t Hash(int32_t value) const = 0;
-
-  /// Compute hash for 64 bits value by using its plain encoding result.
-  ///
-  /// @param value the value to hash.
-  /// @return hash result.
-  virtual uint64_t Hash(int64_t value) const = 0;
-
-  /// Compute hash for float value by using its plain encoding result.
-  ///
-  /// @param value the value to hash.
-  /// @return hash result.
-  virtual uint64_t Hash(float value) const = 0;
-
-  /// Compute hash for double value by using its plain encoding result.
-  ///
-  /// @param value the value to hash.
-  /// @return hash result.
-  virtual uint64_t Hash(double value) const = 0;
-
-  /// Compute hash for Int96 value by using its plain encoding result.
-  ///
-  /// @param value the value to hash.
-  /// @return hash result.
-  virtual uint64_t Hash(const Int96* value) const = 0;
-
-  /// Compute hash for ByteArray value by using its plain encoding result.
-  ///
-  /// @param value the value to hash.
-  /// @return hash result.
-  virtual uint64_t Hash(const ByteArray* value) const = 0;
-
-  /// Compute hash for fixed byte array value by using its plain encoding result.
-  ///
-  /// @param value the value to hash.
-  /// @return hash result.
-  virtual uint64_t Hash(const FLBA* value, uint32_t len) const = 0;
-
-  virtual ~Hasher() = default;
-};
-
-}  // namespace parquet
-
-#endif  // PARQUET_HASHER_H
diff --git a/src/parquet/metadata-test.cc b/src/parquet/metadata-test.cc
deleted file mode 100644
index 53653bd..0000000
--- a/src/parquet/metadata-test.cc
+++ /dev/null
@@ -1,231 +0,0 @@
-// 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.
-
-#include "parquet/metadata.h"
-#include <gtest/gtest.h>
-#include "parquet/schema.h"
-#include "parquet/statistics.h"
-#include "parquet/types.h"
-
-namespace parquet {
-
-namespace metadata {
-
-TEST(Metadata, TestBuildAccess) {
-  parquet::schema::NodeVector fields;
-  parquet::schema::NodePtr root;
-  parquet::SchemaDescriptor schema;
-
-  WriterProperties::Builder prop_builder;
-
-  std::shared_ptr<WriterProperties> props =
-      prop_builder.version(ParquetVersion::PARQUET_2_0)->build();
-
-  fields.push_back(parquet::schema::Int32("int_col", Repetition::REQUIRED));
-  fields.push_back(parquet::schema::Float("float_col", Repetition::REQUIRED));
-  root = parquet::schema::GroupNode::Make("schema", Repetition::REPEATED, fields);
-  schema.Init(root);
-
-  int64_t nrows = 1000;
-  int32_t int_min = 100, int_max = 200;
-  EncodedStatistics stats_int;
-  stats_int.set_null_count(0)
-      .set_distinct_count(nrows)
-      .set_min(std::string(reinterpret_cast<const char*>(&int_min), 4))
-      .set_max(std::string(reinterpret_cast<const char*>(&int_max), 4));
-  EncodedStatistics stats_float;
-  float float_min = 100.100f, float_max = 200.200f;
-  stats_float.set_null_count(0)
-      .set_distinct_count(nrows)
-      .set_min(std::string(reinterpret_cast<const char*>(&float_min), 4))
-      .set_max(std::string(reinterpret_cast<const char*>(&float_max), 4));
-
-  auto f_builder = FileMetaDataBuilder::Make(&schema, props);
-  auto rg1_builder = f_builder->AppendRowGroup();
-  auto rg2_builder = f_builder->AppendRowGroup();
-
-  // Write the metadata
-  // rowgroup1 metadata
-  auto col1_builder = rg1_builder->NextColumnChunk();
-  auto col2_builder = rg1_builder->NextColumnChunk();
-  // column metadata
-  col1_builder->SetStatistics(true, stats_int);
-  col2_builder->SetStatistics(true, stats_float);
-  col1_builder->Finish(nrows / 2, 4, 0, 10, 512, 600, true, false);
-  col2_builder->Finish(nrows / 2, 24, 0, 30, 512, 600, true, false);
-
-  rg1_builder->set_num_rows(nrows / 2);
-  rg1_builder->Finish(1024);
-
-  // rowgroup2 metadata
-  col1_builder = rg2_builder->NextColumnChunk();
-  col2_builder = rg2_builder->NextColumnChunk();
-  // column metadata
-  col1_builder->SetStatistics(true, stats_int);
-  col2_builder->SetStatistics(true, stats_float);
-  col1_builder->Finish(nrows / 2, 6, 0, 10, 512, 600, true, false);
-  col2_builder->Finish(nrows / 2, 16, 0, 26, 512, 600, true, false);
-
-  rg2_builder->set_num_rows(nrows / 2);
-  rg2_builder->Finish(1024);
-
-  // Read the metadata
-  auto f_accessor = f_builder->Finish();
-
-  // file metadata
-  ASSERT_EQ(nrows, f_accessor->num_rows());
-  ASSERT_LE(0, static_cast<int>(f_accessor->size()));
-  ASSERT_EQ(2, f_accessor->num_row_groups());
-  ASSERT_EQ(ParquetVersion::PARQUET_2_0, f_accessor->version());
-  ASSERT_EQ(DEFAULT_CREATED_BY, f_accessor->created_by());
-  ASSERT_EQ(3, f_accessor->num_schema_elements());
-
-  // row group1 metadata
-  auto rg1_accessor = f_accessor->RowGroup(0);
-  ASSERT_EQ(2, rg1_accessor->num_columns());
-  ASSERT_EQ(nrows / 2, rg1_accessor->num_rows());
-  ASSERT_EQ(1024, rg1_accessor->total_byte_size());
-
-  auto rg1_column1 = rg1_accessor->ColumnChunk(0);
-  auto rg1_column2 = rg1_accessor->ColumnChunk(1);
-  ASSERT_EQ(true, rg1_column1->is_stats_set());
-  ASSERT_EQ(true, rg1_column2->is_stats_set());
-  ASSERT_EQ(stats_float.min(), rg1_column2->statistics()->EncodeMin());
-  ASSERT_EQ(stats_float.max(), rg1_column2->statistics()->EncodeMax());
-  ASSERT_EQ(stats_int.min(), rg1_column1->statistics()->EncodeMin());
-  ASSERT_EQ(stats_int.max(), rg1_column1->statistics()->EncodeMax());
-  ASSERT_EQ(0, rg1_column1->statistics()->null_count());
-  ASSERT_EQ(0, rg1_column2->statistics()->null_count());
-  ASSERT_EQ(nrows, rg1_column1->statistics()->distinct_count());
-  ASSERT_EQ(nrows, rg1_column2->statistics()->distinct_count());
-  ASSERT_EQ(DEFAULT_COMPRESSION_TYPE, rg1_column1->compression());
-  ASSERT_EQ(DEFAULT_COMPRESSION_TYPE, rg1_column2->compression());
-  ASSERT_EQ(nrows / 2, rg1_column1->num_values());
-  ASSERT_EQ(nrows / 2, rg1_column2->num_values());
-  ASSERT_EQ(3, rg1_column1->encodings().size());
-  ASSERT_EQ(3, rg1_column2->encodings().size());
-  ASSERT_EQ(512, rg1_column1->total_compressed_size());
-  ASSERT_EQ(512, rg1_column2->total_compressed_size());
-  ASSERT_EQ(600, rg1_column1->total_uncompressed_size());
-  ASSERT_EQ(600, rg1_column2->total_uncompressed_size());
-  ASSERT_EQ(4, rg1_column1->dictionary_page_offset());
-  ASSERT_EQ(24, rg1_column2->dictionary_page_offset());
-  ASSERT_EQ(10, rg1_column1->data_page_offset());
-  ASSERT_EQ(30, rg1_column2->data_page_offset());
-
-  auto rg2_accessor = f_accessor->RowGroup(1);
-  ASSERT_EQ(2, rg2_accessor->num_columns());
-  ASSERT_EQ(nrows / 2, rg2_accessor->num_rows());
-  ASSERT_EQ(1024, rg2_accessor->total_byte_size());
-
-  auto rg2_column1 = rg2_accessor->ColumnChunk(0);
-  auto rg2_column2 = rg2_accessor->ColumnChunk(1);
-  ASSERT_EQ(true, rg2_column1->is_stats_set());
-  ASSERT_EQ(true, rg2_column2->is_stats_set());
-  ASSERT_EQ(stats_float.min(), rg2_column2->statistics()->EncodeMin());
-  ASSERT_EQ(stats_float.max(), rg2_column2->statistics()->EncodeMax());
-  ASSERT_EQ(stats_int.min(), rg1_column1->statistics()->EncodeMin());
-  ASSERT_EQ(stats_int.max(), rg1_column1->statistics()->EncodeMax());
-  ASSERT_EQ(0, rg2_column1->statistics()->null_count());
-  ASSERT_EQ(0, rg2_column2->statistics()->null_count());
-  ASSERT_EQ(nrows, rg2_column1->statistics()->distinct_count());
-  ASSERT_EQ(nrows, rg2_column2->statistics()->distinct_count());
-  ASSERT_EQ(nrows / 2, rg2_column1->num_values());
-  ASSERT_EQ(nrows / 2, rg2_column2->num_values());
-  ASSERT_EQ(DEFAULT_COMPRESSION_TYPE, rg2_column1->compression());
-  ASSERT_EQ(DEFAULT_COMPRESSION_TYPE, rg2_column2->compression());
-  ASSERT_EQ(3, rg2_column1->encodings().size());
-  ASSERT_EQ(3, rg2_column2->encodings().size());
-  ASSERT_EQ(512, rg2_column1->total_compressed_size());
-  ASSERT_EQ(512, rg2_column2->total_compressed_size());
-  ASSERT_EQ(600, rg2_column1->total_uncompressed_size());
-  ASSERT_EQ(600, rg2_column2->total_uncompressed_size());
-  ASSERT_EQ(6, rg2_column1->dictionary_page_offset());
-  ASSERT_EQ(16, rg2_column2->dictionary_page_offset());
-  ASSERT_EQ(10, rg2_column1->data_page_offset());
-  ASSERT_EQ(26, rg2_column2->data_page_offset());
-}
-
-TEST(Metadata, TestV1Version) {
-  // PARQUET-839
-  parquet::schema::NodeVector fields;
-  parquet::schema::NodePtr root;
-  parquet::SchemaDescriptor schema;
-
-  WriterProperties::Builder prop_builder;
-
-  std::shared_ptr<WriterProperties> props =
-      prop_builder.version(ParquetVersion::PARQUET_1_0)->build();
-
-  fields.push_back(parquet::schema::Int32("int_col", Repetition::REQUIRED));
-  fields.push_back(parquet::schema::Float("float_col", Repetition::REQUIRED));
-  root = parquet::schema::GroupNode::Make("schema", Repetition::REPEATED, fields);
-  schema.Init(root);
-
-  auto f_builder = FileMetaDataBuilder::Make(&schema, props);
-
-  // Read the metadata
-  auto f_accessor = f_builder->Finish();
-
-  // file metadata
-  ASSERT_EQ(ParquetVersion::PARQUET_1_0, f_accessor->version());
-}
-
-TEST(ApplicationVersion, Basics) {
-  ApplicationVersion version("parquet-mr version 1.7.9");
-  ApplicationVersion version1("parquet-mr version 1.8.0");
-  ApplicationVersion version2("parquet-cpp version 1.0.0");
-  ApplicationVersion version3("");
-  ApplicationVersion version4("parquet-mr version 1.5.0ab-cdh5.5.0+cd (build abcd)");
-  ApplicationVersion version5("parquet-mr");
-
-  ASSERT_EQ("parquet-mr", version.application_);
-  ASSERT_EQ(1, version.version.major);
-  ASSERT_EQ(7, version.version.minor);
-  ASSERT_EQ(9, version.version.patch);
-
-  ASSERT_EQ("parquet-cpp", version2.application_);
-  ASSERT_EQ(1, version2.version.major);
-  ASSERT_EQ(0, version2.version.minor);
-  ASSERT_EQ(0, version2.version.patch);
-
-  ASSERT_EQ("parquet-mr", version4.application_);
-  ASSERT_EQ("abcd", version4.build_);
-  ASSERT_EQ(1, version4.version.major);
-  ASSERT_EQ(5, version4.version.minor);
-  ASSERT_EQ(0, version4.version.patch);
-  ASSERT_EQ("ab", version4.version.unknown);
-  ASSERT_EQ("cdh5.5.0", version4.version.pre_release);
-  ASSERT_EQ("cd", version4.version.build_info);
-
-  ASSERT_EQ("parquet-mr", version5.application_);
-  ASSERT_EQ(0, version5.version.major);
-  ASSERT_EQ(0, version5.version.minor);
-  ASSERT_EQ(0, version5.version.patch);
-
-  ASSERT_EQ(true, version.VersionLt(version1));
-
-  ASSERT_FALSE(version1.HasCorrectStatistics(Type::INT96, SortOrder::UNKNOWN));
-  ASSERT_TRUE(version.HasCorrectStatistics(Type::INT32, SortOrder::SIGNED));
-  ASSERT_FALSE(version.HasCorrectStatistics(Type::BYTE_ARRAY, SortOrder::SIGNED));
-  ASSERT_TRUE(version1.HasCorrectStatistics(Type::BYTE_ARRAY, SortOrder::SIGNED));
-  ASSERT_TRUE(
-      version3.HasCorrectStatistics(Type::FIXED_LEN_BYTE_ARRAY, SortOrder::SIGNED));
-}
-
-}  // namespace metadata
-}  // namespace parquet
diff --git a/src/parquet/metadata.cc b/src/parquet/metadata.cc
deleted file mode 100644
index 1cab51f..0000000
--- a/src/parquet/metadata.cc
+++ /dev/null
@@ -1,910 +0,0 @@
-// 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.
-
-#include <algorithm>
-#include <string>
-#include <vector>
-
-#include "parquet/exception.h"
-#include "parquet/metadata.h"
-#include "parquet/schema-internal.h"
-#include "parquet/schema.h"
-#include "parquet/thrift.h"
-#include "parquet/util/memory.h"
-
-#include <boost/algorithm/string.hpp>
-#include <boost/regex.hpp>
-
-namespace parquet {
-
-const ApplicationVersion& ApplicationVersion::PARQUET_251_FIXED_VERSION() {
-  static ApplicationVersion version("parquet-mr", 1, 8, 0);
-  return version;
-}
-
-const ApplicationVersion& ApplicationVersion::PARQUET_816_FIXED_VERSION() {
-  static ApplicationVersion version("parquet-mr", 1, 2, 9);
-  return version;
-}
-
-const ApplicationVersion& ApplicationVersion::PARQUET_CPP_FIXED_STATS_VERSION() {
-  static ApplicationVersion version("parquet-cpp", 1, 3, 0);
-  return version;
-}
-
-template <typename DType>
-static std::shared_ptr<RowGroupStatistics> MakeTypedColumnStats(
-    const format::ColumnMetaData& metadata, const ColumnDescriptor* descr) {
-  // If ColumnOrder is defined, return max_value and min_value
-  if (descr->column_order().get_order() == ColumnOrder::TYPE_DEFINED_ORDER) {
-    return std::make_shared<TypedRowGroupStatistics<DType>>(
-        descr, metadata.statistics.min_value, metadata.statistics.max_value,
-        metadata.num_values - metadata.statistics.null_count,
-        metadata.statistics.null_count, metadata.statistics.distinct_count, true);
-  }
-  // Default behavior
-  return std::make_shared<TypedRowGroupStatistics<DType>>(
-      descr, metadata.statistics.min, metadata.statistics.max,
-      metadata.num_values - metadata.statistics.null_count,
-      metadata.statistics.null_count, metadata.statistics.distinct_count,
-      metadata.statistics.__isset.max || metadata.statistics.__isset.min);
-}
-
-std::shared_ptr<RowGroupStatistics> MakeColumnStats(
-    const format::ColumnMetaData& meta_data, const ColumnDescriptor* descr) {
-  switch (static_cast<Type::type>(meta_data.type)) {
-    case Type::BOOLEAN:
-      return MakeTypedColumnStats<BooleanType>(meta_data, descr);
-    case Type::INT32:
-      return MakeTypedColumnStats<Int32Type>(meta_data, descr);
-    case Type::INT64:
-      return MakeTypedColumnStats<Int64Type>(meta_data, descr);
-    case Type::INT96:
-      return MakeTypedColumnStats<Int96Type>(meta_data, descr);
-    case Type::DOUBLE:
-      return MakeTypedColumnStats<DoubleType>(meta_data, descr);
-    case Type::FLOAT:
-      return MakeTypedColumnStats<FloatType>(meta_data, descr);
-    case Type::BYTE_ARRAY:
-      return MakeTypedColumnStats<ByteArrayType>(meta_data, descr);
-    case Type::FIXED_LEN_BYTE_ARRAY:
-      return MakeTypedColumnStats<FLBAType>(meta_data, descr);
-  }
-  throw ParquetException("Can't decode page statistics for selected column type");
-}
-
-// MetaData Accessor
-// ColumnChunk metadata
-class ColumnChunkMetaData::ColumnChunkMetaDataImpl {
- public:
-  explicit ColumnChunkMetaDataImpl(const format::ColumnChunk* column,
-                                   const ColumnDescriptor* descr,
-                                   const ApplicationVersion* writer_version)
-      : column_(column), descr_(descr), writer_version_(writer_version) {
-    const format::ColumnMetaData& meta_data = column->meta_data;
-    for (auto encoding : meta_data.encodings) {
-      encodings_.push_back(FromThrift(encoding));
-    }
-    stats_ = nullptr;
-  }
-  ~ColumnChunkMetaDataImpl() {}
-
-  // column chunk
-  inline int64_t file_offset() const { return column_->file_offset; }
-  inline const std::string& file_path() const { return column_->file_path; }
-
-  // column metadata
-  inline Type::type type() const { return FromThrift(column_->meta_data.type); }
-
-  inline int64_t num_values() const { return column_->meta_data.num_values; }
-
-  std::shared_ptr<schema::ColumnPath> path_in_schema() {
-    return std::make_shared<schema::ColumnPath>(column_->meta_data.path_in_schema);
-  }
-
-  // Check if statistics are set and are valid
-  // 1) Must be set in the metadata
-  // 2) Statistics must not be corrupted
-  // 3) parquet-mr and parquet-cpp write statistics by SIGNED order comparison.
-  //    The statistics are corrupted if the type requires UNSIGNED order comparison.
-  //    Eg: UTF8
-  inline bool is_stats_set() const {
-    DCHECK(writer_version_ != nullptr);
-    return column_->meta_data.__isset.statistics &&
-           writer_version_->HasCorrectStatistics(type(), descr_->sort_order());
-  }
-
-  inline std::shared_ptr<RowGroupStatistics> statistics() const {
-    if (stats_ == nullptr && is_stats_set()) {
-      stats_ = MakeColumnStats(column_->meta_data, descr_);
-    }
-    return stats_;
-  }
-
-  inline Compression::type compression() const {
-    return FromThrift(column_->meta_data.codec);
-  }
-
-  const std::vector<Encoding::type>& encodings() const { return encodings_; }
-
-  inline bool has_dictionary_page() const {
-    return column_->meta_data.__isset.dictionary_page_offset;
-  }
-
-  inline int64_t dictionary_page_offset() const {
-    return column_->meta_data.dictionary_page_offset;
-  }
-
-  inline int64_t data_page_offset() const { return column_->meta_data.data_page_offset; }
-
-  inline bool has_index_page() const {
-    return column_->meta_data.__isset.index_page_offset;
-  }
-
-  inline int64_t index_page_offset() const {
-    return column_->meta_data.index_page_offset;
-  }
-
-  inline int64_t total_compressed_size() const {
-    return column_->meta_data.total_compressed_size;
-  }
-
-  inline int64_t total_uncompressed_size() const {
-    return column_->meta_data.total_uncompressed_size;
-  }
-
- private:
-  mutable std::shared_ptr<RowGroupStatistics> stats_;
-  std::vector<Encoding::type> encodings_;
-  const format::ColumnChunk* column_;
-  const ColumnDescriptor* descr_;
-  const ApplicationVersion* writer_version_;
-};
-
-std::unique_ptr<ColumnChunkMetaData> ColumnChunkMetaData::Make(
-    const uint8_t* metadata, const ColumnDescriptor* descr,
-    const ApplicationVersion* writer_version) {
-  return std::unique_ptr<ColumnChunkMetaData>(
-      new ColumnChunkMetaData(metadata, descr, writer_version));
-}
-
-ColumnChunkMetaData::ColumnChunkMetaData(const uint8_t* metadata,
-                                         const ColumnDescriptor* descr,
-                                         const ApplicationVersion* writer_version)
-    : impl_{std::unique_ptr<ColumnChunkMetaDataImpl>(new ColumnChunkMetaDataImpl(
-          reinterpret_cast<const format::ColumnChunk*>(metadata), descr,
-          writer_version))} {}
-ColumnChunkMetaData::~ColumnChunkMetaData() {}
-
-// column chunk
-int64_t ColumnChunkMetaData::file_offset() const { return impl_->file_offset(); }
-
-const std::string& ColumnChunkMetaData::file_path() const { return impl_->file_path(); }
-
-// column metadata
-Type::type ColumnChunkMetaData::type() const { return impl_->type(); }
-
-int64_t ColumnChunkMetaData::num_values() const { return impl_->num_values(); }
-
-std::shared_ptr<schema::ColumnPath> ColumnChunkMetaData::path_in_schema() const {
-  return impl_->path_in_schema();
-}
-
-std::shared_ptr<RowGroupStatistics> ColumnChunkMetaData::statistics() const {
-  return impl_->statistics();
-}
-
-bool ColumnChunkMetaData::is_stats_set() const { return impl_->is_stats_set(); }
-
-bool ColumnChunkMetaData::has_dictionary_page() const {
-  return impl_->has_dictionary_page();
-}
-
-int64_t ColumnChunkMetaData::dictionary_page_offset() const {
-  return impl_->dictionary_page_offset();
-}
-
-int64_t ColumnChunkMetaData::data_page_offset() const {
-  return impl_->data_page_offset();
-}
-
-bool ColumnChunkMetaData::has_index_page() const { return impl_->has_index_page(); }
-
-int64_t ColumnChunkMetaData::index_page_offset() const {
-  return impl_->index_page_offset();
-}
-
-Compression::type ColumnChunkMetaData::compression() const {
-  return impl_->compression();
-}
-
-const std::vector<Encoding::type>& ColumnChunkMetaData::encodings() const {
-  return impl_->encodings();
-}
-
-int64_t ColumnChunkMetaData::total_uncompressed_size() const {
-  return impl_->total_uncompressed_size();
-}
-
-int64_t ColumnChunkMetaData::total_compressed_size() const {
-  return impl_->total_compressed_size();
-}
-
-// row-group metadata
-class RowGroupMetaData::RowGroupMetaDataImpl {
- public:
-  explicit RowGroupMetaDataImpl(const format::RowGroup* row_group,
-                                const SchemaDescriptor* schema,
-                                const ApplicationVersion* writer_version)
-      : row_group_(row_group), schema_(schema), writer_version_(writer_version) {}
-  ~RowGroupMetaDataImpl() {}
-
-  inline int num_columns() const { return static_cast<int>(row_group_->columns.size()); }
-
-  inline int64_t num_rows() const { return row_group_->num_rows; }
-
-  inline int64_t total_byte_size() const { return row_group_->total_byte_size; }
-
-  inline const SchemaDescriptor* schema() const { return schema_; }
-
-  std::unique_ptr<ColumnChunkMetaData> ColumnChunk(int i) {
-    if (!(i < num_columns())) {
-      std::stringstream ss;
-      ss << "The file only has " << num_columns()
-         << " columns, requested metadata for column: " << i;
-      throw ParquetException(ss.str());
-    }
-    return ColumnChunkMetaData::Make(
-        reinterpret_cast<const uint8_t*>(&row_group_->columns[i]), schema_->Column(i),
-        writer_version_);
-  }
-
- private:
-  const format::RowGroup* row_group_;
-  const SchemaDescriptor* schema_;
-  const ApplicationVersion* writer_version_;
-};
-
-std::unique_ptr<RowGroupMetaData> RowGroupMetaData::Make(
-    const uint8_t* metadata, const SchemaDescriptor* schema,
-    const ApplicationVersion* writer_version) {
-  return std::unique_ptr<RowGroupMetaData>(
-      new RowGroupMetaData(metadata, schema, writer_version));
-}
-
-RowGroupMetaData::RowGroupMetaData(const uint8_t* metadata,
-                                   const SchemaDescriptor* schema,
-                                   const ApplicationVersion* writer_version)
-    : impl_{std::unique_ptr<RowGroupMetaDataImpl>(new RowGroupMetaDataImpl(
-          reinterpret_cast<const format::RowGroup*>(metadata), schema, writer_version))} {
-}
-RowGroupMetaData::~RowGroupMetaData() {}
-
-int RowGroupMetaData::num_columns() const { return impl_->num_columns(); }
-
-int64_t RowGroupMetaData::num_rows() const { return impl_->num_rows(); }
-
-int64_t RowGroupMetaData::total_byte_size() const { return impl_->total_byte_size(); }
-
-const SchemaDescriptor* RowGroupMetaData::schema() const { return impl_->schema(); }
-
-std::unique_ptr<ColumnChunkMetaData> RowGroupMetaData::ColumnChunk(int i) const {
-  return impl_->ColumnChunk(i);
-}
-
-// file metadata
-class FileMetaData::FileMetaDataImpl {
- public:
-  FileMetaDataImpl() : metadata_len_(0) {}
-
-  explicit FileMetaDataImpl(const uint8_t* metadata, uint32_t* metadata_len)
-      : metadata_len_(0) {
-    metadata_.reset(new format::FileMetaData);
-    DeserializeThriftMsg(metadata, metadata_len, metadata_.get());
-    metadata_len_ = *metadata_len;
-
-    if (metadata_->__isset.created_by) {
-      writer_version_ = ApplicationVersion(metadata_->created_by);
-    } else {
-      writer_version_ = ApplicationVersion("unknown 0.0.0");
-    }
-
-    InitSchema();
-    InitColumnOrders();
-    InitKeyValueMetadata();
-  }
-  ~FileMetaDataImpl() {}
-
-  inline uint32_t size() const { return metadata_len_; }
-  inline int num_columns() const { return schema_.num_columns(); }
-  inline int64_t num_rows() const { return metadata_->num_rows; }
-  inline int num_row_groups() const {
-    return static_cast<int>(metadata_->row_groups.size());
-  }
-  inline int32_t version() const { return metadata_->version; }
-  inline const std::string& created_by() const { return metadata_->created_by; }
-  inline int num_schema_elements() const {
-    return static_cast<int>(metadata_->schema.size());
-  }
-
-  const ApplicationVersion& writer_version() const { return writer_version_; }
-
-  void WriteTo(OutputStream* dst) const {
-    SerializeThriftMsg(metadata_.get(), 1024, dst);
-  }
-
-  std::unique_ptr<RowGroupMetaData> RowGroup(int i) {
-    if (!(i < num_row_groups())) {
-      std::stringstream ss;
-      ss << "The file only has " << num_row_groups()
-         << " row groups, requested metadata for row group: " << i;
-      throw ParquetException(ss.str());
-    }
-    return RowGroupMetaData::Make(
-        reinterpret_cast<const uint8_t*>(&metadata_->row_groups[i]), &schema_,
-        &writer_version_);
-  }
-
-  const SchemaDescriptor* schema() const { return &schema_; }
-
-  std::shared_ptr<const KeyValueMetadata> key_value_metadata() const {
-    return key_value_metadata_;
-  }
-
- private:
-  friend FileMetaDataBuilder;
-  uint32_t metadata_len_;
-  std::unique_ptr<format::FileMetaData> metadata_;
-  void InitSchema() {
-    schema::FlatSchemaConverter converter(&metadata_->schema[0],
-                                          static_cast<int>(metadata_->schema.size()));
-    schema_.Init(converter.Convert());
-  }
-  void InitColumnOrders() {
-    // update ColumnOrder
-    std::vector<parquet::ColumnOrder> column_orders;
-    if (metadata_->__isset.column_orders) {
-      for (auto column_order : metadata_->column_orders) {
-        if (column_order.__isset.TYPE_ORDER) {
-          column_orders.push_back(ColumnOrder::type_defined_);
-        } else {
-          column_orders.push_back(ColumnOrder::undefined_);
-        }
-      }
-    } else {
-      column_orders.resize(schema_.num_columns(), ColumnOrder::undefined_);
-    }
-
-    schema_.updateColumnOrders(column_orders);
-  }
-  SchemaDescriptor schema_;
-  ApplicationVersion writer_version_;
-
-  void InitKeyValueMetadata() {
-    std::shared_ptr<KeyValueMetadata> metadata = nullptr;
-    if (metadata_->__isset.key_value_metadata) {
-      metadata = std::make_shared<KeyValueMetadata>();
-      for (const auto& it : metadata_->key_value_metadata) {
-        metadata->Append(it.key, it.value);
-      }
-    }
-    key_value_metadata_ = metadata;
-  }
-
-  std::shared_ptr<const KeyValueMetadata> key_value_metadata_;
-};
-
-std::shared_ptr<FileMetaData> FileMetaData::Make(const uint8_t* metadata,
-                                                 uint32_t* metadata_len) {
-  // This FileMetaData ctor is private, not compatible with std::make_shared
-  return std::shared_ptr<FileMetaData>(new FileMetaData(metadata, metadata_len));
-}
-
-FileMetaData::FileMetaData(const uint8_t* metadata, uint32_t* metadata_len)
-    : impl_{std::unique_ptr<FileMetaDataImpl>(
-          new FileMetaDataImpl(metadata, metadata_len))} {}
-
-FileMetaData::FileMetaData()
-    : impl_{std::unique_ptr<FileMetaDataImpl>(new FileMetaDataImpl())} {}
-
-FileMetaData::~FileMetaData() {}
-
-std::unique_ptr<RowGroupMetaData> FileMetaData::RowGroup(int i) const {
-  return impl_->RowGroup(i);
-}
-
-uint32_t FileMetaData::size() const { return impl_->size(); }
-
-int FileMetaData::num_columns() const { return impl_->num_columns(); }
-
-int64_t FileMetaData::num_rows() const { return impl_->num_rows(); }
-
-int FileMetaData::num_row_groups() const { return impl_->num_row_groups(); }
-
-ParquetVersion::type FileMetaData::version() const {
-  switch (impl_->version()) {
-    case 1:
-      return ParquetVersion::PARQUET_1_0;
-    case 2:
-      return ParquetVersion::PARQUET_2_0;
-    default:
-      // Improperly set version, assuming Parquet 1.0
-      break;
-  }
-  return ParquetVersion::PARQUET_1_0;
-}
-
-const ApplicationVersion& FileMetaData::writer_version() const {
-  return impl_->writer_version();
-}
-
-const std::string& FileMetaData::created_by() const { return impl_->created_by(); }
-
-int FileMetaData::num_schema_elements() const { return impl_->num_schema_elements(); }
-
-const SchemaDescriptor* FileMetaData::schema() const { return impl_->schema(); }
-
-std::shared_ptr<const KeyValueMetadata> FileMetaData::key_value_metadata() const {
-  return impl_->key_value_metadata();
-}
-
-void FileMetaData::WriteTo(OutputStream* dst) const { return impl_->WriteTo(dst); }
-
-ApplicationVersion::ApplicationVersion(const std::string& application, int major,
-                                       int minor, int patch)
-    : application_(application), version{major, minor, patch, "", "", ""} {}
-
-ApplicationVersion::ApplicationVersion(const std::string& created_by) {
-  boost::regex app_regex{ApplicationVersion::APPLICATION_FORMAT};
-  boost::regex ver_regex{ApplicationVersion::VERSION_FORMAT};
-  boost::smatch app_matches;
-  boost::smatch ver_matches;
-
-  std::string created_by_lower = created_by;
-  std::transform(created_by_lower.begin(), created_by_lower.end(),
-                 created_by_lower.begin(), ::tolower);
-
-  bool app_success = boost::regex_match(created_by_lower, app_matches, app_regex);
-  bool ver_success = false;
-  std::string version_str;
-
-  if (app_success && app_matches.size() >= 4) {
-    // first match is the entire string. sub-matches start from second.
-    application_ = app_matches[1];
-    version_str = app_matches[3];
-    build_ = app_matches[4];
-    ver_success = boost::regex_match(version_str, ver_matches, ver_regex);
-  } else {
-    application_ = "unknown";
-  }
-
-  if (ver_success && ver_matches.size() >= 7) {
-    version.major = atoi(ver_matches[1].str().c_str());
-    version.minor = atoi(ver_matches[2].str().c_str());
-    version.patch = atoi(ver_matches[3].str().c_str());
-    version.unknown = ver_matches[4].str();
-    version.pre_release = ver_matches[5].str();
-    version.build_info = ver_matches[6].str();
-  } else {
-    version.major = 0;
-    version.minor = 0;
-    version.patch = 0;
-  }
-}
-
-bool ApplicationVersion::VersionLt(const ApplicationVersion& other_version) const {
-  if (application_ != other_version.application_) return false;
-
-  if (version.major < other_version.version.major) return true;
-  if (version.major > other_version.version.major) return false;
-  DCHECK_EQ(version.major, other_version.version.major);
-  if (version.minor < other_version.version.minor) return true;
-  if (version.minor > other_version.version.minor) return false;
-  DCHECK_EQ(version.minor, other_version.version.minor);
-  return version.patch < other_version.version.patch;
-}
-
-bool ApplicationVersion::VersionEq(const ApplicationVersion& other_version) const {
-  return application_ == other_version.application_ &&
-         version.major == other_version.version.major &&
-         version.minor == other_version.version.minor &&
-         version.patch == other_version.version.patch;
-}
-
-// Reference:
-// parquet-mr/parquet-column/src/main/java/org/apache/parquet/CorruptStatistics.java
-// PARQUET-686 has more disussion on statistics
-bool ApplicationVersion::HasCorrectStatistics(Type::type col_type,
-                                              SortOrder::type sort_order) const {
-  // Parquet cpp version 1.3.0 onwards stats are computed correctly for all types
-  if ((application_ != "parquet-cpp") || (VersionLt(PARQUET_CPP_FIXED_STATS_VERSION()))) {
-    // Only SIGNED are valid
-    if (SortOrder::SIGNED != sort_order) {
-      return false;
-    }
-
-    // Statistics of other types are OK
-    if (col_type != Type::FIXED_LEN_BYTE_ARRAY && col_type != Type::BYTE_ARRAY) {
-      return true;
-    }
-  }
-  // created_by is not populated, which could have been caused by
-  // parquet-mr during the same time as PARQUET-251, see PARQUET-297
-  if (application_ == "unknown") {
-    return true;
-  }
-
-  // Unknown sort order has incorrect stats
-  if (SortOrder::UNKNOWN == sort_order) {
-    return false;
-  }
-
-  // PARQUET-251
-  if (VersionLt(PARQUET_251_FIXED_VERSION())) {
-    return false;
-  }
-
-  return true;
-}
-
-// MetaData Builders
-// row-group metadata
-class ColumnChunkMetaDataBuilder::ColumnChunkMetaDataBuilderImpl {
- public:
-  explicit ColumnChunkMetaDataBuilderImpl(const std::shared_ptr<WriterProperties>& props,
-                                          const ColumnDescriptor* column,
-                                          uint8_t* contents)
-      : properties_(props), column_(column) {
-    column_chunk_ = reinterpret_cast<format::ColumnChunk*>(contents);
-    column_chunk_->meta_data.__set_type(ToThrift(column->physical_type()));
-    column_chunk_->meta_data.__set_path_in_schema(column->path()->ToDotVector());
-    column_chunk_->meta_data.__set_codec(
-        ToThrift(properties_->compression(column->path())));
-  }
-  ~ColumnChunkMetaDataBuilderImpl() {}
-
-  // column chunk
-  void set_file_path(const std::string& val) { column_chunk_->__set_file_path(val); }
-
-  // column metadata
-  void SetStatistics(bool is_signed, const EncodedStatistics& val) {
-    format::Statistics stats;
-    stats.null_count = val.null_count;
-    stats.distinct_count = val.distinct_count;
-    stats.max_value = val.max();
-    stats.min_value = val.min();
-    stats.__isset.min_value = val.has_min;
-    stats.__isset.max_value = val.has_max;
-    stats.__isset.null_count = val.has_null_count;
-    stats.__isset.distinct_count = val.has_distinct_count;
-    // If the order is SIGNED, then the old min/max values must be set too.
-    // This for backward compatibility
-    if (is_signed) {
-      stats.max = val.max();
-      stats.min = val.min();
-      stats.__isset.min = val.has_min;
-      stats.__isset.max = val.has_max;
-    }
-
-    column_chunk_->meta_data.__set_statistics(stats);
-  }
-
-  void Finish(int64_t num_values, int64_t dictionary_page_offset,
-              int64_t index_page_offset, int64_t data_page_offset,
-              int64_t compressed_size, int64_t uncompressed_size, bool has_dictionary,
-              bool dictionary_fallback) {
-    if (dictionary_page_offset > 0) {
-      column_chunk_->meta_data.__set_dictionary_page_offset(dictionary_page_offset);
-      column_chunk_->__set_file_offset(dictionary_page_offset + compressed_size);
-    } else {
-      column_chunk_->__set_file_offset(data_page_offset + compressed_size);
-    }
-    column_chunk_->__isset.meta_data = true;
-    column_chunk_->meta_data.__set_num_values(num_values);
-    if (index_page_offset >= 0) {
-      column_chunk_->meta_data.__set_index_page_offset(index_page_offset);
-    }
-    column_chunk_->meta_data.__set_data_page_offset(data_page_offset);
-    column_chunk_->meta_data.__set_total_uncompressed_size(uncompressed_size);
-    column_chunk_->meta_data.__set_total_compressed_size(compressed_size);
-    std::vector<format::Encoding::type> thrift_encodings;
-    if (has_dictionary) {
-      thrift_encodings.push_back(ToThrift(properties_->dictionary_index_encoding()));
-      if (properties_->version() == ParquetVersion::PARQUET_1_0) {
-        thrift_encodings.push_back(ToThrift(Encoding::PLAIN));
-      } else {
-        thrift_encodings.push_back(ToThrift(properties_->dictionary_page_encoding()));
-      }
-    } else {  // Dictionary not enabled
-      thrift_encodings.push_back(ToThrift(properties_->encoding(column_->path())));
-    }
-    thrift_encodings.push_back(ToThrift(Encoding::RLE));
-    // Only PLAIN encoding is supported for fallback in V1
-    // TODO(majetideepak): Use user specified encoding for V2
-    if (dictionary_fallback) {
-      thrift_encodings.push_back(ToThrift(Encoding::PLAIN));
-    }
-    column_chunk_->meta_data.__set_encodings(thrift_encodings);
-  }
-
-  void WriteTo(OutputStream* sink) {
-    SerializeThriftMsg(column_chunk_, sizeof(format::ColumnChunk), sink);
-  }
-
-  const ColumnDescriptor* descr() const { return column_; }
-
- private:
-  format::ColumnChunk* column_chunk_;
-  const std::shared_ptr<WriterProperties> properties_;
-  const ColumnDescriptor* column_;
-};
-
-std::unique_ptr<ColumnChunkMetaDataBuilder> ColumnChunkMetaDataBuilder::Make(
-    const std::shared_ptr<WriterProperties>& props, const ColumnDescriptor* column,
-    uint8_t* contents) {
-  return std::unique_ptr<ColumnChunkMetaDataBuilder>(
-      new ColumnChunkMetaDataBuilder(props, column, contents));
-}
-
-ColumnChunkMetaDataBuilder::ColumnChunkMetaDataBuilder(
-    const std::shared_ptr<WriterProperties>& props, const ColumnDescriptor* column,
-    uint8_t* contents)
-    : impl_{std::unique_ptr<ColumnChunkMetaDataBuilderImpl>(
-          new ColumnChunkMetaDataBuilderImpl(props, column, contents))} {}
-
-ColumnChunkMetaDataBuilder::~ColumnChunkMetaDataBuilder() {}
-
-void ColumnChunkMetaDataBuilder::set_file_path(const std::string& path) {
-  impl_->set_file_path(path);
-}
-
-void ColumnChunkMetaDataBuilder::Finish(int64_t num_values,
-                                        int64_t dictionary_page_offset,
-                                        int64_t index_page_offset,
-                                        int64_t data_page_offset, int64_t compressed_size,
-                                        int64_t uncompressed_size, bool has_dictionary,
-                                        bool dictionary_fallback) {
-  impl_->Finish(num_values, dictionary_page_offset, index_page_offset, data_page_offset,
-                compressed_size, uncompressed_size, has_dictionary, dictionary_fallback);
-}
-
-void ColumnChunkMetaDataBuilder::WriteTo(OutputStream* sink) { impl_->WriteTo(sink); }
-
-const ColumnDescriptor* ColumnChunkMetaDataBuilder::descr() const {
-  return impl_->descr();
-}
-
-void ColumnChunkMetaDataBuilder::SetStatistics(bool is_signed,
-                                               const EncodedStatistics& result) {
-  impl_->SetStatistics(is_signed, result);
-}
-
-class RowGroupMetaDataBuilder::RowGroupMetaDataBuilderImpl {
- public:
-  explicit RowGroupMetaDataBuilderImpl(const std::shared_ptr<WriterProperties>& props,
-                                       const SchemaDescriptor* schema, uint8_t* contents)
-      : properties_(props), schema_(schema), current_column_(0) {
-    row_group_ = reinterpret_cast<format::RowGroup*>(contents);
-    InitializeColumns(schema->num_columns());
-  }
-  ~RowGroupMetaDataBuilderImpl() {}
-
-  ColumnChunkMetaDataBuilder* NextColumnChunk() {
-    if (!(current_column_ < num_columns())) {
-      std::stringstream ss;
-      ss << "The schema only has " << num_columns()
-         << " columns, requested metadata for column: " << current_column_;
-      throw ParquetException(ss.str());
-    }
-    auto column = schema_->Column(current_column_);
-    auto column_builder = ColumnChunkMetaDataBuilder::Make(
-        properties_, column,
-        reinterpret_cast<uint8_t*>(&row_group_->columns[current_column_++]));
-    auto column_builder_ptr = column_builder.get();
-    column_builders_.push_back(std::move(column_builder));
-    return column_builder_ptr;
-  }
-
-  int current_column() { return current_column_; }
-
-  void Finish(int64_t total_bytes_written) {
-    if (!(current_column_ == schema_->num_columns())) {
-      std::stringstream ss;
-      ss << "Only " << current_column_ - 1 << " out of " << schema_->num_columns()
-         << " columns are initialized";
-      throw ParquetException(ss.str());
-    }
-    int64_t total_byte_size = 0;
-
-    for (int i = 0; i < schema_->num_columns(); i++) {
-      if (!(row_group_->columns[i].file_offset >= 0)) {
-        std::stringstream ss;
-        ss << "Column " << i << " is not complete.";
-        throw ParquetException(ss.str());
-      }
-      total_byte_size += row_group_->columns[i].meta_data.total_compressed_size;
-    }
-    DCHECK(total_bytes_written == total_byte_size)
-        << "Total bytes in this RowGroup does not match with compressed sizes of columns";
-
-    row_group_->__set_total_byte_size(total_byte_size);
-  }
-
-  void set_num_rows(int64_t num_rows) { row_group_->num_rows = num_rows; }
-
-  int num_columns() { return static_cast<int>(row_group_->columns.size()); }
-
-  int64_t num_rows() { return row_group_->num_rows; }
-
- private:
-  void InitializeColumns(int ncols) { row_group_->columns.resize(ncols); }
-
-  format::RowGroup* row_group_;
-  const std::shared_ptr<WriterProperties> properties_;
-  const SchemaDescriptor* schema_;
-  std::vector<std::unique_ptr<ColumnChunkMetaDataBuilder>> column_builders_;
-  int current_column_;
-};
-
-std::unique_ptr<RowGroupMetaDataBuilder> RowGroupMetaDataBuilder::Make(
-    const std::shared_ptr<WriterProperties>& props, const SchemaDescriptor* schema_,
-    uint8_t* contents) {
-  return std::unique_ptr<RowGroupMetaDataBuilder>(
-      new RowGroupMetaDataBuilder(props, schema_, contents));
-}
-
-RowGroupMetaDataBuilder::RowGroupMetaDataBuilder(
-    const std::shared_ptr<WriterProperties>& props, const SchemaDescriptor* schema_,
-    uint8_t* contents)
-    : impl_{std::unique_ptr<RowGroupMetaDataBuilderImpl>(
-          new RowGroupMetaDataBuilderImpl(props, schema_, contents))} {}
-
-RowGroupMetaDataBuilder::~RowGroupMetaDataBuilder() {}
-
-ColumnChunkMetaDataBuilder* RowGroupMetaDataBuilder::NextColumnChunk() {
-  return impl_->NextColumnChunk();
-}
-
-int RowGroupMetaDataBuilder::current_column() const { return impl_->current_column(); }
-
-int RowGroupMetaDataBuilder::num_columns() { return impl_->num_columns(); }
-
-int64_t RowGroupMetaDataBuilder::num_rows() { return impl_->num_rows(); }
-
-void RowGroupMetaDataBuilder::set_num_rows(int64_t num_rows) {
-  impl_->set_num_rows(num_rows);
-}
-
-void RowGroupMetaDataBuilder::Finish(int64_t total_bytes_written) {
-  impl_->Finish(total_bytes_written);
-}
-
-// file metadata
-// TODO(PARQUET-595) Support key_value_metadata
-class FileMetaDataBuilder::FileMetaDataBuilderImpl {
- public:
-  explicit FileMetaDataBuilderImpl(
-      const SchemaDescriptor* schema, const std::shared_ptr<WriterProperties>& props,
-      const std::shared_ptr<const KeyValueMetadata>& key_value_metadata)
-      : properties_(props), schema_(schema), key_value_metadata_(key_value_metadata) {
-    metadata_.reset(new format::FileMetaData());
-  }
-  ~FileMetaDataBuilderImpl() {}
-
-  RowGroupMetaDataBuilder* AppendRowGroup() {
-    auto row_group = std::unique_ptr<format::RowGroup>(new format::RowGroup());
-    auto row_group_builder = RowGroupMetaDataBuilder::Make(
-        properties_, schema_, reinterpret_cast<uint8_t*>(row_group.get()));
-    RowGroupMetaDataBuilder* row_group_ptr = row_group_builder.get();
-    row_group_builders_.push_back(std::move(row_group_builder));
-    row_groups_.push_back(std::move(row_group));
-    return row_group_ptr;
-  }
-
-  std::unique_ptr<FileMetaData> Finish() {
-    int64_t total_rows = 0;
-    std::vector<format::RowGroup> row_groups;
-    for (auto row_group = row_groups_.begin(); row_group != row_groups_.end();
-         row_group++) {
-      auto rowgroup = *((*row_group).get());
-      row_groups.push_back(rowgroup);
-      total_rows += rowgroup.num_rows;
-    }
-    metadata_->__set_num_rows(total_rows);
-    metadata_->__set_row_groups(row_groups);
-
-    if (key_value_metadata_) {
-      metadata_->key_value_metadata.clear();
-      metadata_->key_value_metadata.reserve(key_value_metadata_->size());
-      for (int64_t i = 0; i < key_value_metadata_->size(); ++i) {
-        format::KeyValue kv_pair;
-        kv_pair.__set_key(key_value_metadata_->key(i));
-        kv_pair.__set_value(key_value_metadata_->value(i));
-        metadata_->key_value_metadata.push_back(kv_pair);
-      }
-      metadata_->__isset.key_value_metadata = true;
-    }
-
-    int32_t file_version = 0;
-    switch (properties_->version()) {
-      case ParquetVersion::PARQUET_1_0:
-        file_version = 1;
-        break;
-      case ParquetVersion::PARQUET_2_0:
-        file_version = 2;
-        break;
-      default:
-        break;
-    }
-    metadata_->__set_version(file_version);
-    metadata_->__set_created_by(properties_->created_by());
-
-    // Users cannot set the `ColumnOrder` since we donot not have user defined sort order
-    // in the spec yet.
-    // We always default to `TYPE_DEFINED_ORDER`. We can expose it in
-    // the API once we have user defined sort orders in the Parquet format.
-    // TypeDefinedOrder implies choose SortOrder based on LogicalType/PhysicalType
-    format::TypeDefinedOrder type_defined_order;
-    format::ColumnOrder column_order;
-    column_order.__set_TYPE_ORDER(type_defined_order);
-    column_order.__isset.TYPE_ORDER = true;
-    metadata_->column_orders.resize(schema_->num_columns(), column_order);
-    metadata_->__isset.column_orders = true;
-
-    parquet::schema::SchemaFlattener flattener(
-        static_cast<parquet::schema::GroupNode*>(schema_->schema_root().get()),
-        &metadata_->schema);
-    flattener.Flatten();
-    auto file_meta_data = std::unique_ptr<FileMetaData>(new FileMetaData());
-    file_meta_data->impl_->metadata_ = std::move(metadata_);
-    file_meta_data->impl_->InitSchema();
-    return file_meta_data;
-  }
-
- protected:
-  std::unique_ptr<format::FileMetaData> metadata_;
-
- private:
-  const std::shared_ptr<WriterProperties> properties_;
-  std::vector<std::unique_ptr<format::RowGroup>> row_groups_;
-  std::vector<std::unique_ptr<RowGroupMetaDataBuilder>> row_group_builders_;
-  const SchemaDescriptor* schema_;
-  std::shared_ptr<const KeyValueMetadata> key_value_metadata_;
-};
-
-std::unique_ptr<FileMetaDataBuilder> FileMetaDataBuilder::Make(
-    const SchemaDescriptor* schema, const std::shared_ptr<WriterProperties>& props,
-    const std::shared_ptr<const KeyValueMetadata>& key_value_metadata) {
-  return std::unique_ptr<FileMetaDataBuilder>(
-      new FileMetaDataBuilder(schema, props, key_value_metadata));
-}
-
-FileMetaDataBuilder::FileMetaDataBuilder(
-    const SchemaDescriptor* schema, const std::shared_ptr<WriterProperties>& props,
-    const std::shared_ptr<const KeyValueMetadata>& key_value_metadata)
-    : impl_{std::unique_ptr<FileMetaDataBuilderImpl>(
-          new FileMetaDataBuilderImpl(schema, props, key_value_metadata))} {}
-
-FileMetaDataBuilder::~FileMetaDataBuilder() {}
-
-RowGroupMetaDataBuilder* FileMetaDataBuilder::AppendRowGroup() {
-  return impl_->AppendRowGroup();
-}
-
-std::unique_ptr<FileMetaData> FileMetaDataBuilder::Finish() { return impl_->Finish(); }
-
-}  // namespace parquet
diff --git a/src/parquet/metadata.h b/src/parquet/metadata.h
deleted file mode 100644
index 5d51e3d..0000000
--- a/src/parquet/metadata.h
+++ /dev/null
@@ -1,277 +0,0 @@
-// 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.
-
-#ifndef PARQUET_FILE_METADATA_H
-#define PARQUET_FILE_METADATA_H
-
-#include <set>
-#include <string>
-#include <vector>
-
-#include "arrow/util/key_value_metadata.h"
-
-#include "parquet/properties.h"
-#include "parquet/schema.h"
-#include "parquet/statistics.h"
-#include "parquet/types.h"
-#include "parquet/util/memory.h"
-#include "parquet/util/visibility.h"
-
-namespace parquet {
-
-using KeyValueMetadata = ::arrow::KeyValueMetadata;
-
-class ApplicationVersion {
- public:
-  // Known Versions with Issues
-  static const ApplicationVersion& PARQUET_251_FIXED_VERSION();
-  static const ApplicationVersion& PARQUET_816_FIXED_VERSION();
-  static const ApplicationVersion& PARQUET_CPP_FIXED_STATS_VERSION();
-  // Regular expression for the version format
-  // major . minor . patch unknown - prerelease.x + build info
-  // Eg: 1.5.0ab-cdh5.5.0+cd
-  static constexpr char const* VERSION_FORMAT =
-      "^(\\d+)\\.(\\d+)\\.(\\d+)([^-+]*)?(?:-([^+]*))?(?:\\+(.*))?$";
-  // Regular expression for the application format
-  // application_name version VERSION_FORMAT (build build_name)
-  // Eg: parquet-cpp version 1.5.0ab-xyz5.5.0+cd (build abcd)
-  static constexpr char const* APPLICATION_FORMAT =
-      "(.*?)\\s*(?:(version\\s*(?:([^(]*?)\\s*(?:\\(\\s*build\\s*([^)]*?)\\s*\\))?)?)?)";
-
-  // Application that wrote the file. e.g. "IMPALA"
-  std::string application_;
-  // Build name
-  std::string build_;
-
-  // Version of the application that wrote the file, expressed as
-  // (<major>.<minor>.<patch>). Unmatched parts default to 0.
-  // "1.2.3"    => {1, 2, 3}
-  // "1.2"      => {0, 0, 0}
-  // "1.2-cdh5" => {0, 0, 0}
-  // TODO (majetideepak): Implement support for pre_release
-  struct {
-    int major;
-    int minor;
-    int patch;
-    std::string unknown;
-    std::string pre_release;
-    std::string build_info;
-  } version;
-
-  ApplicationVersion() {}
-  explicit ApplicationVersion(const std::string& created_by);
-  ApplicationVersion(const std::string& application, int major, int minor, int patch);
-
-  // Returns true if version is strictly less than other_version
-  bool VersionLt(const ApplicationVersion& other_version) const;
-
-  // Returns true if version is strictly less than other_version
-  bool VersionEq(const ApplicationVersion& other_version) const;
-
-  // Checks if the Version has the correct statistics for a given column
-  bool HasCorrectStatistics(Type::type primitive,
-                            SortOrder::type sort_order = SortOrder::SIGNED) const;
-};
-
-class PARQUET_EXPORT ColumnChunkMetaData {
- public:
-  // API convenience to get a MetaData accessor
-  static std::unique_ptr<ColumnChunkMetaData> Make(
-      const uint8_t* metadata, const ColumnDescriptor* descr,
-      const ApplicationVersion* writer_version = nullptr);
-
-  ~ColumnChunkMetaData();
-
-  // column chunk
-  int64_t file_offset() const;
-  // parameter is only used when a dataset is spread across multiple files
-  const std::string& file_path() const;
-  // column metadata
-  Type::type type() const;
-  int64_t num_values() const;
-  std::shared_ptr<schema::ColumnPath> path_in_schema() const;
-  bool is_stats_set() const;
-  std::shared_ptr<RowGroupStatistics> statistics() const;
-  Compression::type compression() const;
-  const std::vector<Encoding::type>& encodings() const;
-  bool has_dictionary_page() const;
-  int64_t dictionary_page_offset() const;
-  int64_t data_page_offset() const;
-  bool has_index_page() const;
-  int64_t index_page_offset() const;
-  int64_t total_compressed_size() const;
-  int64_t total_uncompressed_size() const;
-
- private:
-  explicit ColumnChunkMetaData(const uint8_t* metadata, const ColumnDescriptor* descr,
-                               const ApplicationVersion* writer_version = nullptr);
-  // PIMPL Idiom
-  class ColumnChunkMetaDataImpl;
-  std::unique_ptr<ColumnChunkMetaDataImpl> impl_;
-};
-
-class PARQUET_EXPORT RowGroupMetaData {
- public:
-  // API convenience to get a MetaData accessor
-  static std::unique_ptr<RowGroupMetaData> Make(
-      const uint8_t* metadata, const SchemaDescriptor* schema,
-      const ApplicationVersion* writer_version = nullptr);
-
-  ~RowGroupMetaData();
-
-  // row-group metadata
-  int num_columns() const;
-  int64_t num_rows() const;
-  int64_t total_byte_size() const;
-  // Return const-pointer to make it clear that this object is not to be copied
-  const SchemaDescriptor* schema() const;
-  std::unique_ptr<ColumnChunkMetaData> ColumnChunk(int i) const;
-
- private:
-  explicit RowGroupMetaData(const uint8_t* metadata, const SchemaDescriptor* schema,
-                            const ApplicationVersion* writer_version = nullptr);
-  // PIMPL Idiom
-  class RowGroupMetaDataImpl;
-  std::unique_ptr<RowGroupMetaDataImpl> impl_;
-};
-
-class FileMetaDataBuilder;
-
-class PARQUET_EXPORT FileMetaData {
- public:
-  // API convenience to get a MetaData accessor
-  static std::shared_ptr<FileMetaData> Make(const uint8_t* serialized_metadata,
-                                            uint32_t* metadata_len);
-
-  ~FileMetaData();
-
-  // file metadata
-  uint32_t size() const;
-  int num_columns() const;
-  int64_t num_rows() const;
-  int num_row_groups() const;
-  ParquetVersion::type version() const;
-  const std::string& created_by() const;
-  int num_schema_elements() const;
-  std::unique_ptr<RowGroupMetaData> RowGroup(int i) const;
-
-  const ApplicationVersion& writer_version() const;
-
-  void WriteTo(OutputStream* dst) const;
-
-  // Return const-pointer to make it clear that this object is not to be copied
-  const SchemaDescriptor* schema() const;
-
-  std::shared_ptr<const KeyValueMetadata> key_value_metadata() const;
-
- private:
-  friend FileMetaDataBuilder;
-  explicit FileMetaData(const uint8_t* serialized_metadata, uint32_t* metadata_len);
-
-  // PIMPL Idiom
-  FileMetaData();
-  class FileMetaDataImpl;
-  std::unique_ptr<FileMetaDataImpl> impl_;
-};
-
-// Builder API
-class PARQUET_EXPORT ColumnChunkMetaDataBuilder {
- public:
-  // API convenience to get a MetaData reader
-  static std::unique_ptr<ColumnChunkMetaDataBuilder> Make(
-      const std::shared_ptr<WriterProperties>& props, const ColumnDescriptor* column,
-      uint8_t* contents);
-
-  ~ColumnChunkMetaDataBuilder();
-
-  // column chunk
-  // Used when a dataset is spread across multiple files
-  void set_file_path(const std::string& path);
-  // column metadata
-  void SetStatistics(bool is_signed, const EncodedStatistics& stats);
-  // get the column descriptor
-  const ColumnDescriptor* descr() const;
-  // commit the metadata
-  void Finish(int64_t num_values, int64_t dictonary_page_offset,
-              int64_t index_page_offset, int64_t data_page_offset,
-              int64_t compressed_size, int64_t uncompressed_size, bool has_dictionary,
-              bool dictionary_fallback);
-
-  // For writing metadata at end of column chunk
-  void WriteTo(OutputStream* sink);
-
- private:
-  explicit ColumnChunkMetaDataBuilder(const std::shared_ptr<WriterProperties>& props,
-                                      const ColumnDescriptor* column, uint8_t* contents);
-  // PIMPL Idiom
-  class ColumnChunkMetaDataBuilderImpl;
-  std::unique_ptr<ColumnChunkMetaDataBuilderImpl> impl_;
-};
-
-class PARQUET_EXPORT RowGroupMetaDataBuilder {
- public:
-  // API convenience to get a MetaData reader
-  static std::unique_ptr<RowGroupMetaDataBuilder> Make(
-      const std::shared_ptr<WriterProperties>& props, const SchemaDescriptor* schema_,
-      uint8_t* contents);
-
-  ~RowGroupMetaDataBuilder();
-
-  ColumnChunkMetaDataBuilder* NextColumnChunk();
-  int num_columns();
-  int64_t num_rows();
-  int current_column() const;
-
-  void set_num_rows(int64_t num_rows);
-
-  // commit the metadata
-  void Finish(int64_t total_bytes_written);
-
- private:
-  explicit RowGroupMetaDataBuilder(const std::shared_ptr<WriterProperties>& props,
-                                   const SchemaDescriptor* schema_, uint8_t* contents);
-  // PIMPL Idiom
-  class RowGroupMetaDataBuilderImpl;
-  std::unique_ptr<RowGroupMetaDataBuilderImpl> impl_;
-};
-
-class PARQUET_EXPORT FileMetaDataBuilder {
- public:
-  // API convenience to get a MetaData reader
-  static std::unique_ptr<FileMetaDataBuilder> Make(
-      const SchemaDescriptor* schema, const std::shared_ptr<WriterProperties>& props,
-      const std::shared_ptr<const KeyValueMetadata>& key_value_metadata = nullptr);
-
-  ~FileMetaDataBuilder();
-
-  RowGroupMetaDataBuilder* AppendRowGroup();
-
-  // commit the metadata
-  std::unique_ptr<FileMetaData> Finish();
-
- private:
-  explicit FileMetaDataBuilder(
-      const SchemaDescriptor* schema, const std::shared_ptr<WriterProperties>& props,
-      const std::shared_ptr<const KeyValueMetadata>& key_value_metadata = nullptr);
-  // PIMPL Idiom
-  class FileMetaDataBuilderImpl;
-  std::unique_ptr<FileMetaDataBuilderImpl> impl_;
-};
-
-}  // namespace parquet
-
-#endif  // PARQUET_FILE_METADATA_H
diff --git a/src/parquet/murmur3.cc b/src/parquet/murmur3.cc
deleted file mode 100644
index a19436e..0000000
--- a/src/parquet/murmur3.cc
+++ /dev/null
@@ -1,222 +0,0 @@
-// 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.
-
-//-----------------------------------------------------------------------------
-// MurmurHash3 was written by Austin Appleby, and is placed in the public
-// domain. The author hereby disclaims copyright to this source code.
-
-// Note - The x86 and x64 versions do _not_ produce the same results, as the
-// algorithms are optimized for their respective platforms. You can still
-// compile and run any of them on any platform, but your performance with the
-// non-native version will be less than optimal.
-
-#include "parquet/murmur3.h"
-
-namespace parquet {
-
-#if defined(_MSC_VER)
-
-#define FORCE_INLINE __forceinline
-#define ROTL64(x, y) _rotl64(x, y)
-
-#else  // defined(_MSC_VER)
-
-#define FORCE_INLINE inline __attribute__((always_inline))
-inline uint64_t rotl64(uint64_t x, int8_t r) { return (x << r) | (x >> (64 - r)); }
-#define ROTL64(x, y) rotl64(x, y)
-
-#endif  // !defined(_MSC_VER)
-
-#define BIG_CONSTANT(x) (x##LLU)
-
-//-----------------------------------------------------------------------------
-// Block read - if your platform needs to do endian-swapping or can only
-// handle aligned reads, do the conversion here
-
-FORCE_INLINE uint32_t getblock32(const uint32_t* p, int i) { return p[i]; }
-
-FORCE_INLINE uint64_t getblock64(const uint64_t* p, int i) { return p[i]; }
-
-//-----------------------------------------------------------------------------
-// Finalization mix - force all bits of a hash block to avalanche
-
-FORCE_INLINE uint32_t fmix32(uint32_t h) {
-  h ^= h >> 16;
-  h *= 0x85ebca6b;
-  h ^= h >> 13;
-  h *= 0xc2b2ae35;
-  h ^= h >> 16;
-
-  return h;
-}
-
-//----------
-
-FORCE_INLINE uint64_t fmix64(uint64_t k) {
-  k ^= k >> 33;
-  k *= BIG_CONSTANT(0xff51afd7ed558ccd);
-  k ^= k >> 33;
-  k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
-  k ^= k >> 33;
-
-  return k;
-}
-
-//-----------------------------------------------------------------------------
-
-void Hash_x64_128(const void* key, const int len, const uint32_t seed, uint64_t out[2]) {
-  const uint8_t* data = (const uint8_t*)key;
-  const int nblocks = len / 16;
-
-  uint64_t h1 = seed;
-  uint64_t h2 = seed;
-
-  const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
-  const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
-
-  //----------
-  // body
-
-  const uint64_t* blocks = (const uint64_t*)(data);
-
-  for (int i = 0; i < nblocks; i++) {
-    uint64_t k1 = getblock64(blocks, i * 2 + 0);
-    uint64_t k2 = getblock64(blocks, i * 2 + 1);
-
-    k1 *= c1;
-    k1 = ROTL64(k1, 31);
-    k1 *= c2;
-    h1 ^= k1;
-
-    h1 = ROTL64(h1, 27);
-    h1 += h2;
-    h1 = h1 * 5 + 0x52dce729;
-
-    k2 *= c2;
-    k2 = ROTL64(k2, 33);
-    k2 *= c1;
-    h2 ^= k2;
-
-    h2 = ROTL64(h2, 31);
-    h2 += h1;
-    h2 = h2 * 5 + 0x38495ab5;
-  }
-
-  //----------
-  // tail
-
-  const uint8_t* tail = (const uint8_t*)(data + nblocks * 16);
-
-  uint64_t k1 = 0;
-  uint64_t k2 = 0;
-
-  switch (len & 15) {
-    case 15:
-      k2 ^= ((uint64_t)tail[14]) << 48;
-    case 14:
-      k2 ^= ((uint64_t)tail[13]) << 40;
-    case 13:
-      k2 ^= ((uint64_t)tail[12]) << 32;
-    case 12:
-      k2 ^= ((uint64_t)tail[11]) << 24;
-    case 11:
-      k2 ^= ((uint64_t)tail[10]) << 16;
-    case 10:
-      k2 ^= ((uint64_t)tail[9]) << 8;
-    case 9:
-      k2 ^= ((uint64_t)tail[8]) << 0;
-      k2 *= c2;
-      k2 = ROTL64(k2, 33);
-      k2 *= c1;
-      h2 ^= k2;
-
-    case 8:
-      k1 ^= ((uint64_t)tail[7]) << 56;
-    case 7:
-      k1 ^= ((uint64_t)tail[6]) << 48;
-    case 6:
-      k1 ^= ((uint64_t)tail[5]) << 40;
-    case 5:
-      k1 ^= ((uint64_t)tail[4]) << 32;
-    case 4:
-      k1 ^= ((uint64_t)tail[3]) << 24;
-    case 3:
-      k1 ^= ((uint64_t)tail[2]) << 16;
-    case 2:
-      k1 ^= ((uint64_t)tail[1]) << 8;
-    case 1:
-      k1 ^= ((uint64_t)tail[0]) << 0;
-      k1 *= c1;
-      k1 = ROTL64(k1, 31);
-      k1 *= c2;
-      h1 ^= k1;
-  }
-
-  //----------
-  // finalization
-
-  h1 ^= len;
-  h2 ^= len;
-
-  h1 += h2;
-  h2 += h1;
-
-  h1 = fmix64(h1);
-  h2 = fmix64(h2);
-
-  h1 += h2;
-  h2 += h1;
-
-  reinterpret_cast<uint64_t*>(out)[0] = h1;
-  reinterpret_cast<uint64_t*>(out)[1] = h2;
-}
-
-template <typename T>
-uint64_t HashHelper(T value, uint32_t seed) {
-  uint64_t output[2];
-  Hash_x64_128(reinterpret_cast<void*>(&value), sizeof(T), seed, output);
-  return output[0];
-}
-
-uint64_t MurmurHash3::Hash(int32_t value) const { return HashHelper(value, seed_); }
-
-uint64_t MurmurHash3::Hash(int64_t value) const { return HashHelper(value, seed_); }
-
-uint64_t MurmurHash3::Hash(float value) const { return HashHelper(value, seed_); }
-
-uint64_t MurmurHash3::Hash(double value) const { return HashHelper(value, seed_); }
-
-uint64_t MurmurHash3::Hash(const FLBA* value, uint32_t len) const {
-  uint64_t out[2];
-  Hash_x64_128(reinterpret_cast<const void*>(value->ptr), len, seed_, out);
-  return out[0];
-}
-
-uint64_t MurmurHash3::Hash(const Int96* value) const {
-  uint64_t out[2];
-  Hash_x64_128(reinterpret_cast<const void*>(value->value), sizeof(value->value), seed_,
-               out);
-  return out[0];
-}
-
-uint64_t MurmurHash3::Hash(const ByteArray* value) const {
-  uint64_t out[2];
-  Hash_x64_128(reinterpret_cast<const void*>(value->ptr), value->len, seed_, out);
-  return out[0];
-}
-
-}  // namespace parquet
diff --git a/src/parquet/murmur3.h b/src/parquet/murmur3.h
deleted file mode 100644
index 84792f3..0000000
--- a/src/parquet/murmur3.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// 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.
-
-//-----------------------------------------------------------------------------
-// MurmurHash3 was written by Austin Appleby, and is placed in the public
-// domain. The author hereby disclaims copyright to this source code.
-
-#ifndef PARQUET_MURMURHASH3_H_
-#define PARQUET_MURMURHASH3_H_
-
-#include <cstdint>
-
-#include "parquet/hasher.h"
-#include "parquet/types.h"
-
-namespace parquet {
-
-/// Source:
-/// https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp
-/// (Modified to adapt to coding conventions and to inherit the Hasher abstract class)
-class MurmurHash3 : public Hasher {
- public:
-  MurmurHash3() : seed_(DEFAULT_SEED) {}
-  uint64_t Hash(int32_t value) const override;
-  uint64_t Hash(int64_t value) const override;
-  uint64_t Hash(float value) const override;
-  uint64_t Hash(double value) const override;
-  uint64_t Hash(const Int96* value) const override;
-  uint64_t Hash(const ByteArray* value) const override;
-  uint64_t Hash(const FLBA* val, uint32_t len) const override;
-
- private:
-  // Default seed for hash which comes from Bloom filter in parquet-mr, it is generated
-  // by System.nanoTime() of java.
-  static constexpr int DEFAULT_SEED = 1361930890;
-
-  uint32_t seed_;
-};
-
-}  // namespace parquet
-
-#endif  // PARQUET_MURMURHASH3_H_
diff --git a/src/parquet/parquet.pc.in b/src/parquet/parquet.pc.in
deleted file mode 100644
index 9313d1f..0000000
--- a/src/parquet/parquet.pc.in
+++ /dev/null
@@ -1,29 +0,0 @@
-# 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.
-
-prefix=@CMAKE_INSTALL_PREFIX@
-libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
-includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
-
-so_version=@PARQUET_SO_VERSION@
-abi_version=@PARQUET_ABI_VERSION@
-
-Name: Apache Parquet
-Description: Apache Parquet is a columnar storage format.
-Version: @PARQUET_VERSION@
-Libs: -L${libdir} -lparquet
-Cflags: -I${includedir}
diff --git a/src/parquet/parquet.thrift b/src/parquet/parquet.thrift
deleted file mode 100644
index aec8e54..0000000
--- a/src/parquet/parquet.thrift
+++ /dev/null
@@ -1,924 +0,0 @@
-/**
- * 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.
- */
-
-cpp_include "parquet/util/windows_compatibility.h"
-
-/**
- * File format description for the parquet file format
- */
-namespace cpp parquet.format
-namespace java org.apache.parquet.format
-
-/**
- * Types supported by Parquet.  These types are intended to be used in combination
- * with the encodings to control the on disk storage format.
- * For example INT16 is not included as a type since a good encoding of INT32
- * would handle this.
- */
-enum Type {
-  BOOLEAN = 0;
-  INT32 = 1;
-  INT64 = 2;
-  INT96 = 3;
-  FLOAT = 4;
-  DOUBLE = 5;
-  BYTE_ARRAY = 6;
-  FIXED_LEN_BYTE_ARRAY = 7;
-}
-
-/**
- * Common types used by frameworks(e.g. hive, pig) using parquet.  This helps map
- * between types in those frameworks to the base types in parquet.  This is only
- * metadata and not needed to read or write the data.
- */
-enum ConvertedType {
-  /** a BYTE_ARRAY actually contains UTF8 encoded chars */
-  UTF8 = 0;
-
-  /** a map is converted as an optional field containing a repeated key/value pair */
-  MAP = 1;
-
-  /** a key/value pair is converted into a group of two fields */
-  MAP_KEY_VALUE = 2;
-
-  /** a list is converted into an optional field containing a repeated field for its
-   * values */
-  LIST = 3;
-
-  /** an enum is converted into a binary field */
-  ENUM = 4;
-
-  /**
-   * A decimal value.
-   *
-   * This may be used to annotate binary or fixed primitive types. The
-   * underlying byte array stores the unscaled value encoded as two's
-   * complement using big-endian byte order (the most significant byte is the
-   * zeroth element). The value of the decimal is the value * 10^{-scale}.
-   *
-   * This must be accompanied by a (maximum) precision and a scale in the
-   * SchemaElement. The precision specifies the number of digits in the decimal
-   * and the scale stores the location of the decimal point. For example 1.23
-   * would have precision 3 (3 total digits) and scale 2 (the decimal point is
-   * 2 digits over).
-   */
-  DECIMAL = 5;
-
-  /**
-   * A Date
-   *
-   * Stored as days since Unix epoch, encoded as the INT32 physical type.
-   *
-   */
-  DATE = 6;
-
-  /**
-   * A time
-   *
-   * The total number of milliseconds since midnight.  The value is stored
-   * as an INT32 physical type.
-   */
-  TIME_MILLIS = 7;
-
-  /**
-   * A time.
-   *
-   * The total number of microseconds since midnight.  The value is stored as
-   * an INT64 physical type.
-   */
-  TIME_MICROS = 8;
-
-  /**
-   * A date/time combination
-   *
-   * Date and time recorded as milliseconds since the Unix epoch.  Recorded as
-   * a physical type of INT64.
-   */
-  TIMESTAMP_MILLIS = 9;
-
-  /**
-   * A date/time combination
-   *
-   * Date and time recorded as microseconds since the Unix epoch.  The value is
-   * stored as an INT64 physical type.
-   */
-  TIMESTAMP_MICROS = 10;
-
-
-  /**
-   * An unsigned integer value.
-   *
-   * The number describes the maximum number of meainful data bits in
-   * the stored value. 8, 16 and 32 bit values are stored using the
-   * INT32 physical type.  64 bit values are stored using the INT64
-   * physical type.
-   *
-   */
-  UINT_8 = 11;
-  UINT_16 = 12;
-  UINT_32 = 13;
-  UINT_64 = 14;
-
-  /**
-   * A signed integer value.
-   *
-   * The number describes the maximum number of meainful data bits in
-   * the stored value. 8, 16 and 32 bit values are stored using the
-   * INT32 physical type.  64 bit values are stored using the INT64
-   * physical type.
-   *
-   */
-  INT_8 = 15;
-  INT_16 = 16;
-  INT_32 = 17;
-  INT_64 = 18;
-
-  /**
-   * An embedded JSON document
-   *
-   * A JSON document embedded within a single UTF8 column.
-   */
-  JSON = 19;
-
-  /**
-   * An embedded BSON document
-   *
-   * A BSON document embedded within a single BINARY column.
-   */
-  BSON = 20;
-
-  /**
-   * An interval of time
-   *
-   * This type annotates data stored as a FIXED_LEN_BYTE_ARRAY of length 12
-   * This data is composed of three separate little endian unsigned
-   * integers.  Each stores a component of a duration of time.  The first
-   * integer identifies the number of months associated with the duration,
-   * the second identifies the number of days associated with the duration
-   * and the third identifies the number of milliseconds associated with
-   * the provided duration.  This duration of time is independent of any
-   * particular timezone or date.
-   */
-  INTERVAL = 21;
-}
-
-/**
- * Representation of Schemas
- */
-enum FieldRepetitionType {
-  /** This field is required (can not be null) and each record has exactly 1 value. */
-  REQUIRED = 0;
-
-  /** The field is optional (can be null) and each record has 0 or 1 values. */
-  OPTIONAL = 1;
-
-  /** The field is repeated and can contain 0 or more values */
-  REPEATED = 2;
-}
-
-/**
- * Statistics per row group and per page
- * All fields are optional.
- */
-struct Statistics {
-   /**
-    * DEPRECATED: min and max value of the column. Use min_value and max_value.
-    *
-    * Values are encoded using PLAIN encoding, except that variable-length byte
-    * arrays do not include a length prefix.
-    *
-    * These fields encode min and max values determined by signed comparison
-    * only. New files should use the correct order for a column's logical type
-    * and store the values in the min_value and max_value fields.
-    *
-    * To support older readers, these may be set when the column order is
-    * signed.
-    */
-   1: optional binary max;
-   2: optional binary min;
-   /** count of null value in the column */
-   3: optional i64 null_count;
-   /** count of distinct values occurring */
-   4: optional i64 distinct_count;
-   /**
-    * Min and max values for the column, determined by its ColumnOrder.
-    *
-    * Values are encoded using PLAIN encoding, except that variable-length byte
-    * arrays do not include a length prefix.
-    */
-   5: optional binary max_value;
-   6: optional binary min_value;
-}
-
-/** Empty structs to use as logical type annotations */
-struct StringType {}  // allowed for BINARY, must be encoded with UTF-8
-struct UUIDType {}    // allowed for FIXED[16], must encoded raw UUID bytes
-struct MapType {}     // see LogicalTypes.md
-struct ListType {}    // see LogicalTypes.md
-struct EnumType {}    // allowed for BINARY, must be encoded with UTF-8
-struct DateType {}    // allowed for INT32
-
-/**
- * Logical type to annotate a column that is always null.
- *
- * Sometimes when discovering the schema of existing data, values are always
- * null and the physical type can't be determined. This annotation signals
- * the case where the physical type was guessed from all null values.
- */
-struct NullType {}    // allowed for any physical type, only null values stored
-
-/**
- * Decimal logical type annotation
- *
- * To maintain forward-compatibility in v1, implementations using this logical
- * type must also set scale and precision on the annotated SchemaElement.
- *
- * Allowed for physical types: INT32, INT64, FIXED, and BINARY
- */
-struct DecimalType {
-  1: required i32 scale
-  2: required i32 precision
-}
-
-/** Time units for logical types */
-struct MilliSeconds {}
-struct MicroSeconds {}
-union TimeUnit {
-  1: MilliSeconds MILLIS
-  2: MicroSeconds MICROS
-}
-
-/**
- * Timestamp logical type annotation
- *
- * Allowed for physical types: INT64
- */
-struct TimestampType {
-  1: required bool isAdjustedToUTC
-  2: required TimeUnit unit
-}
-
-/**
- * Time logical type annotation
- *
- * Allowed for physical types: INT32 (millis), INT64 (micros)
- */
-struct TimeType {
-  1: required bool isAdjustedToUTC
-  2: required TimeUnit unit
-}
-
-/**
- * Integer logical type annotation
- *
- * bitWidth must be 8, 16, 32, or 64.
- *
- * Allowed for physical types: INT32, INT64
- */
-struct IntType {
-  1: required byte bitWidth
-  2: required bool isSigned
-}
-
-/**
- * Embedded JSON logical type annotation
- *
- * Allowed for physical types: BINARY
- */
-struct JsonType {
-}
-
-/**
- * Embedded BSON logical type annotation
- *
- * Allowed for physical types: BINARY
- */
-struct BsonType {
-}
-
-/**
- * LogicalType annotations to replace ConvertedType.
- *
- * To maintain compatibility, implementations using LogicalType for a
- * SchemaElement must also set the corresponding ConvertedType from the
- * following table.
- */
-union LogicalType {
-  1:  StringType STRING       // use ConvertedType UTF8 if encoding is UTF-8
-  2:  MapType MAP             // use ConvertedType MAP
-  3:  ListType LIST           // use ConvertedType LIST
-  4:  EnumType ENUM           // use ConvertedType ENUM
-  5:  DecimalType DECIMAL     // use ConvertedType DECIMAL
-  6:  DateType DATE           // use ConvertedType DATE
-  7:  TimeType TIME           // use ConvertedType TIME_MICROS or TIME_MILLIS
-  8:  TimestampType TIMESTAMP // use ConvertedType TIMESTAMP_MICROS or TIMESTAMP_MILLIS
-  // 9: reserved for INTERVAL
-  10: IntType INTEGER         // use ConvertedType INT_* or UINT_*
-  11: NullType UNKNOWN        // no compatible ConvertedType
-  12: JsonType JSON           // use ConvertedType JSON
-  13: BsonType BSON           // use ConvertedType BSON
-}
-
-/**
- * Represents a element inside a schema definition.
- *  - if it is a group (inner node) then type is undefined and num_children is defined
- *  - if it is a primitive type (leaf) then type is defined and num_children is undefined
- * the nodes are listed in depth first traversal order.
- */
-struct SchemaElement {
-  /** Data type for this field. Not set if the current element is a non-leaf node */
-  1: optional Type type;
-
-  /** If type is FIXED_LEN_BYTE_ARRAY, this is the byte length of the vales.
-   * Otherwise, if specified, this is the maximum bit length to store any of the values.
-   * (e.g. a low cardinality INT col could have this set to 3).  Note that this is
-   * in the schema, and therefore fixed for the entire file.
-   */
-  2: optional i32 type_length;
-
-  /** repetition of the field. The root of the schema does not have a repetition_type.
-   * All other nodes must have one */
-  3: optional FieldRepetitionType repetition_type;
-
-  /** Name of the field in the schema */
-  4: required string name;
-
-  /** Nested fields.  Since thrift does not support nested fields,
-   * the nesting is flattened to a single list by a depth-first traversal.
-   * The children count is used to construct the nested relationship.
-   * This field is not set when the element is a primitive type
-   */
-  5: optional i32 num_children;
-
-  /** When the schema is the result of a conversion from another model
-   * Used to record the original type to help with cross conversion.
-   */
-  6: optional ConvertedType converted_type;
-
-  /** Used when this column contains decimal data.
-   * See the DECIMAL converted type for more details.
-   */
-  7: optional i32 scale
-  8: optional i32 precision
-
-  /** When the original schema supports field ids, this will save the
-   * original field id in the parquet schema
-   */
-  9: optional i32 field_id;
-
-  /**
-   * The logical type of this SchemaElement; only valid for primitives.
-   *
-   * LogicalType replaces ConvertedType, but ConvertedType is still required
-   * for some logical types to ensure forward-compatibility in format v1.
-   */
-  10: optional LogicalType logicalType
-}
-
-/**
- * Encodings supported by Parquet.  Not all encodings are valid for all types.  These
- * enums are also used to specify the encoding of definition and repetition levels.
- * See the accompanying doc for the details of the more complicated encodings.
- */
-enum Encoding {
-  /** Default encoding.
-   * BOOLEAN - 1 bit per value. 0 is false; 1 is true.
-   * INT32 - 4 bytes per value.  Stored as little-endian.
-   * INT64 - 8 bytes per value.  Stored as little-endian.
-   * FLOAT - 4 bytes per value.  IEEE. Stored as little-endian.
-   * DOUBLE - 8 bytes per value.  IEEE. Stored as little-endian.
-   * BYTE_ARRAY - 4 byte length stored as little endian, followed by bytes.
-   * FIXED_LEN_BYTE_ARRAY - Just the bytes.
-   */
-  PLAIN = 0;
-
-  /** Group VarInt encoding for INT32/INT64.
-   * This encoding is deprecated. It was never used
-   */
-  //  GROUP_VAR_INT = 1;
-
-  /**
-   * Deprecated: Dictionary encoding. The values in the dictionary are encoded in the
-   * plain type.
-   * in a data page use RLE_DICTIONARY instead.
-   * in a Dictionary page use PLAIN instead
-   */
-  PLAIN_DICTIONARY = 2;
-
-  /** Group packed run length encoding. Usable for definition/repetition levels
-   * encoding and Booleans (on one bit: 0 is false; 1 is true.)
-   */
-  RLE = 3;
-
-  /** Bit packed encoding.  This can only be used if the data has a known max
-   * width.  Usable for definition/repetition levels encoding.
-   */
-  BIT_PACKED = 4;
-
-  /** Delta encoding for integers. This can be used for int columns and works best
-   * on sorted data
-   */
-  DELTA_BINARY_PACKED = 5;
-
-  /** Encoding for byte arrays to separate the length values and the data. The lengths
-   * are encoded using DELTA_BINARY_PACKED
-   */
-  DELTA_LENGTH_BYTE_ARRAY = 6;
-
-  /** Incremental-encoded byte array. Prefix lengths are encoded using DELTA_BINARY_PACKED.
-   * Suffixes are stored as delta length byte arrays.
-   */
-  DELTA_BYTE_ARRAY = 7;
-
-  /** Dictionary encoding: the ids are encoded using the RLE encoding
-   */
-  RLE_DICTIONARY = 8;
-}
-
-/**
- * Supported compression algorithms.
- *
- * Codecs added in 2.3.2 can be read by readers based on 2.3.2 and later.
- * Codec support may vary between readers based on the format version and
- * libraries available at runtime. Gzip, Snappy, and LZ4 codecs are
- * widely available, while Zstd and Brotli require additional libraries.
- */
-enum CompressionCodec {
-  UNCOMPRESSED = 0;
-  SNAPPY = 1;
-  GZIP = 2;
-  LZO = 3;
-  BROTLI = 4; // Added in 2.3.2
-  LZ4 = 5;    // Added in 2.3.2
-  ZSTD = 6;   // Added in 2.3.2
-}
-
-enum PageType {
-  DATA_PAGE = 0;
-  INDEX_PAGE = 1;
-  DICTIONARY_PAGE = 2;
-  DATA_PAGE_V2 = 3;
-}
-
-/**
- * Enum to annotate whether lists of min/max elements inside ColumnIndex
- * are ordered and if so, in which direction.
- */
-enum BoundaryOrder {
-  UNORDERED = 0;
-  ASCENDING = 1;
-  DESCENDING = 2;
-}
-
-/** Data page header */
-struct DataPageHeader {
-  /** Number of values, including NULLs, in this data page. **/
-  1: required i32 num_values
-
-  /** Encoding used for this data page **/
-  2: required Encoding encoding
-
-  /** Encoding used for definition levels **/
-  3: required Encoding definition_level_encoding;
-
-  /** Encoding used for repetition levels **/
-  4: required Encoding repetition_level_encoding;
-
-  /** Optional statistics for the data in this page**/
-  5: optional Statistics statistics;
-}
-
-struct IndexPageHeader {
-  /** TODO: **/
-}
-
-struct DictionaryPageHeader {
-  /** Number of values in the dictionary **/
-  1: required i32 num_values;
-
-  /** Encoding using this dictionary page **/
-  2: required Encoding encoding
-
-  /** If true, the entries in the dictionary are sorted in ascending order **/
-  3: optional bool is_sorted;
-}
-
-/**
- * New page format allowing reading levels without decompressing the data
- * Repetition and definition levels are uncompressed
- * The remaining section containing the data is compressed if is_compressed is true
- **/
-struct DataPageHeaderV2 {
-  /** Number of values, including NULLs, in this data page. **/
-  1: required i32 num_values
-  /** Number of NULL values, in this data page.
-      Number of non-null = num_values - num_nulls which is also the number of values in the data section **/
-  2: required i32 num_nulls
-  /** Number of rows in this data page. which means pages change on record boundaries (r = 0) **/
-  3: required i32 num_rows
-  /** Encoding used for data in this page **/
-  4: required Encoding encoding
-
-  // repetition levels and definition levels are always using RLE (without size in it)
-
-  /** length of the definition levels */
-  5: required i32 definition_levels_byte_length;
-  /** length of the repetition levels */
-  6: required i32 repetition_levels_byte_length;
-
-  /**  whether the values are compressed.
-  Which means the section of the page between
-  definition_levels_byte_length + repetition_levels_byte_length + 1 and compressed_page_size (included)
-  is compressed with the compression_codec.
-  If missing it is considered compressed */
-  7: optional bool is_compressed = 1;
-
-  /** optional statistics for this column chunk */
-  8: optional Statistics statistics;
-}
-
-struct PageHeader {
-  /** the type of the page: indicates which of the *_header fields is set **/
-  1: required PageType type
-
-  /** Uncompressed page size in bytes (not including this header) **/
-  2: required i32 uncompressed_page_size
-
-  /** Compressed page size in bytes (not including this header) **/
-  3: required i32 compressed_page_size
-
-  /** 32bit crc for the data below. This allows for disabling checksumming in HDFS
-   *  if only a few pages needs to be read
-   **/
-  4: optional i32 crc
-
-  // Headers for page specific data.  One only will be set.
-  5: optional DataPageHeader data_page_header;
-  6: optional IndexPageHeader index_page_header;
-  7: optional DictionaryPageHeader dictionary_page_header;
-  8: optional DataPageHeaderV2 data_page_header_v2;
-}
-
-/**
- * Wrapper struct to store key values
- */
- struct KeyValue {
-  1: required string key
-  2: optional string value
-}
-
-/**
- * Wrapper struct to specify sort order
- */
-struct SortingColumn {
-  /** The column index (in this row group) **/
-  1: required i32 column_idx
-
-  /** If true, indicates this column is sorted in descending order. **/
-  2: required bool descending
-
-  /** If true, nulls will come before non-null values, otherwise,
-   * nulls go at the end. */
-  3: required bool nulls_first
-}
-
-/**
- * statistics of a given page type and encoding
- */
-struct PageEncodingStats {
-
-  /** the page type (data/dic/...) **/
-  1: required PageType page_type;
-
-  /** encoding of the page **/
-  2: required Encoding encoding;
-
-  /** number of pages of this type with this encoding **/
-  3: required i32 count;
-
-}
-
-/**
- * Description for column metadata
- */
-struct ColumnMetaData {
-  /** Type of this column **/
-  1: required Type type
-
-  /** Set of all encodings used for this column. The purpose is to validate
-   * whether we can decode those pages. **/
-  2: required list<Encoding> encodings
-
-  /** Path in schema **/
-  3: required list<string> path_in_schema
-
-  /** Compression codec **/
-  4: required CompressionCodec codec
-
-  /** Number of values in this column **/
-  5: required i64 num_values
-
-  /** total byte size of all uncompressed pages in this column chunk (including the headers) **/
-  6: required i64 total_uncompressed_size
-
-  /** total byte size of all compressed pages in this column chunk (including the headers) **/
-  7: required i64 total_compressed_size
-
-  /** Optional key/value metadata **/
-  8: optional list<KeyValue> key_value_metadata
-
-  /** Byte offset from beginning of file to first data page **/
-  9: required i64 data_page_offset
-
-  /** Byte offset from beginning of file to root index page **/
-  10: optional i64 index_page_offset
-
-  /** Byte offset from the beginning of file to first (only) dictionary page **/
-  11: optional i64 dictionary_page_offset
-
-  /** optional statistics for this column chunk */
-  12: optional Statistics statistics;
-
-  /** Set of all encodings used for pages in this column chunk.
-   * This information can be used to determine if all data pages are
-   * dictionary encoded for example **/
-  13: optional list<PageEncodingStats> encoding_stats;
-}
-
-struct EncryptionWithFooterKey {
-}
-
-struct EncryptionWithColumnKey {
-  /** Column path in schema **/
-  1: required list<string> path_in_schema
-  
-  /** Retrieval metadata of the column-specific key **/
-  2: optional binary column_key_metadata
-}
-
-union ColumnCryptoMetaData {
-  1: EncryptionWithFooterKey ENCRYPTION_WITH_FOOTER_KEY
-  2: EncryptionWithColumnKey ENCRYPTION_WITH_COLUMN_KEY
-}
-
-struct ColumnChunk {
-  /** File where column data is stored.  If not set, assumed to be same file as
-    * metadata.  This path is relative to the current file.
-    **/
-  1: optional string file_path
-
-  /** Byte offset in file_path to the ColumnMetaData **/
-  2: required i64 file_offset
-
-  /** Column metadata for this chunk. This is the same content as what is at
-   * file_path/file_offset.  Having it here has it replicated in the file
-   * metadata.
-   **/
-  3: optional ColumnMetaData meta_data
-
-  /** File offset of ColumnChunk's OffsetIndex **/
-  4: optional i64 offset_index_offset
-
-  /** Size of ColumnChunk's OffsetIndex, in bytes **/
-  5: optional i32 offset_index_length
-
-  /** File offset of ColumnChunk's ColumnIndex **/
-  6: optional i64 column_index_offset
-
-  /** Size of ColumnChunk's ColumnIndex, in bytes **/
-  7: optional i32 column_index_length
-  
-  /** Crypto metadata of encrypted columns **/
-  8: optional ColumnCryptoMetaData crypto_meta_data
-}
-
-struct RowGroup {
-  /** Metadata for each column chunk in this row group.
-   * This list must have the same order as the SchemaElement list in FileMetaData.
-   **/
-  1: required list<ColumnChunk> columns
-
-  /** Total byte size of all the uncompressed column data in this row group **/
-  2: required i64 total_byte_size
-
-  /** Number of rows in this row group **/
-  3: required i64 num_rows
-
-  /** If set, specifies a sort ordering of the rows in this RowGroup.
-   * The sorting columns can be a subset of all the columns.
-   */
-  4: optional list<SortingColumn> sorting_columns
-}
-
-/** Empty struct to signal the order defined by the physical or logical type */
-struct TypeDefinedOrder {}
-
-/**
- * Union to specify the order used for the min_value and max_value fields for a
- * column. This union takes the role of an enhanced enum that allows rich
- * elements (which will be needed for a collation-based ordering in the future).
- *
- * Possible values are:
- * * TypeDefinedOrder - the column uses the order defined by its logical or
- *                      physical type (if there is no logical type).
- *
- * If the reader does not support the value of this union, min and max stats
- * for this column should be ignored.
- */
-union ColumnOrder {
-
-  /**
-   * The sort orders for logical types are:
-   *   UTF8 - unsigned byte-wise comparison
-   *   INT8 - signed comparison
-   *   INT16 - signed comparison
-   *   INT32 - signed comparison
-   *   INT64 - signed comparison
-   *   UINT8 - unsigned comparison
-   *   UINT16 - unsigned comparison
-   *   UINT32 - unsigned comparison
-   *   UINT64 - unsigned comparison
-   *   DECIMAL - signed comparison of the represented value
-   *   DATE - signed comparison
-   *   TIME_MILLIS - signed comparison
-   *   TIME_MICROS - signed comparison
-   *   TIMESTAMP_MILLIS - signed comparison
-   *   TIMESTAMP_MICROS - signed comparison
-   *   INTERVAL - unsigned comparison
-   *   JSON - unsigned byte-wise comparison
-   *   BSON - unsigned byte-wise comparison
-   *   ENUM - unsigned byte-wise comparison
-   *   LIST - undefined
-   *   MAP - undefined
-   *
-   * In the absence of logical types, the sort order is determined by the physical type:
-   *   BOOLEAN - false, true
-   *   INT32 - signed comparison
-   *   INT64 - signed comparison
-   *   INT96 (only used for legacy timestamps) - unsigned comparison
-   *   FLOAT - signed comparison of the represented value
-   *   DOUBLE - signed comparison of the represented value
-   *   BYTE_ARRAY - unsigned byte-wise comparison
-   *   FIXED_LEN_BYTE_ARRAY - unsigned byte-wise comparison
-   */
-  1: TypeDefinedOrder TYPE_ORDER;
-}
-
-struct PageLocation {
-  /** Offset of the page in the file **/
-  1: required i64 offset
-
-  /**
-   * Size of the page, including header. Sum of compressed_page_size and header
-   * length
-   */
-  2: required i32 compressed_page_size
-
-  /**
-   * Index within the RowGroup of the first row of the page; this means pages
-   * change on record boundaries (r = 0).
-   */
-  3: required i64 first_row_index
-}
-
-struct OffsetIndex {
-  /**
-   * PageLocations, ordered by increasing PageLocation.offset. It is required
-   * that page_locations[i].first_row_index < page_locations[i+1].first_row_index.
-   */
-  1: required list<PageLocation> page_locations
-}
-
-/**
- * Description for ColumnIndex.
- * Each <array-field>[i] refers to the page at OffsetIndex.page_locations[i]
- */
-struct ColumnIndex {
-  /**
-   * A list of Boolean values to determine the validity of the corresponding
-   * min and max values. If true, a page contains only null values, and writers
-   * have to set the corresponding entries in min_values and max_values to
-   * byte[0], so that all lists have the same length. If false, the
-   * corresponding entries in min_values and max_values must be valid.
-   */
-  1: required list<bool> null_pages
-
-  /**
-   * Two lists containing lower and upper bounds for the values of each page.
-   * These may be the actual minimum and maximum values found on a page, but
-   * can also be (more compact) values that do not exist on a page. For
-   * example, instead of storing ""Blart Versenwald III", a writer may set
-   * min_values[i]="B", max_values[i]="C". Such more compact values must still
-   * be valid values within the column's logical type. Readers must make sure
-   * that list entries are populated before using them by inspecting null_pages.
-   */
-  2: required list<binary> min_values
-  3: required list<binary> max_values
-
-  /**
-   * Stores whether both min_values and max_values are orderd and if so, in
-   * which direction. This allows readers to perform binary searches in both
-   * lists. Readers cannot assume that max_values[i] <= min_values[i+1], even
-   * if the lists are ordered.
-   */
-  4: required BoundaryOrder boundary_order
-
-  /** A list containing the number of null values for each page **/
-  5: optional list<i64> null_counts
-}
-
-/**
- * Description for file metadata
- */
-struct FileMetaData {
-  /** Version of this file **/
-  1: required i32 version
-
-  /** Parquet schema for this file.  This schema contains metadata for all the columns.
-   * The schema is represented as a tree with a single root.  The nodes of the tree
-   * are flattened to a list by doing a depth-first traversal.
-   * The column metadata contains the path in the schema for that column which can be
-   * used to map columns to nodes in the schema.
-   * The first element is the root **/
-  2: required list<SchemaElement> schema;
-
-  /** Number of rows in this file **/
-  3: required i64 num_rows
-
-  /** Row groups in this file **/
-  4: required list<RowGroup> row_groups
-
-  /** Optional key/value metadata **/
-  5: optional list<KeyValue> key_value_metadata
-
-  /** String for application that wrote this file.  This should be in the format
-   * <Application> version <App Version> (build <App Build Hash>).
-   * e.g. impala version 1.0 (build 6cf94d29b2b7115df4de2c06e2ab4326d721eb55)
-   **/
-  6: optional string created_by
-
-  /**
-   * Sort order used for the min_value and max_value fields of each column in
-   * this file. Each sort order corresponds to one column, determined by its
-   * position in the list, matching the position of the column in the schema.
-   *
-   * Without column_orders, the meaning of the min_value and max_value fields is
-   * undefined. To ensure well-defined behaviour, if min_value and max_value are
-   * written to a Parquet file, column_orders must be written as well.
-   *
-   * The obsolete min and max fields are always sorted by signed comparison
-   * regardless of column_orders.
-   */
-  7: optional list<ColumnOrder> column_orders;
-}
-
-struct AesGcmV1 {
-  /** Retrieval metadata of AAD used for encryption of pages and structures **/
-  1: optional binary aad_metadata
-}
-
-struct AesGcmCtrV1 {
-  /** Retrieval metadata of AAD used for encryption of structures **/
-  1: optional binary aad_metadata
-}
-
-union EncryptionAlgorithm {
-  1: AesGcmV1 AES_GCM_V1
-  2: AesGcmCtrV1 AES_GCM_CTR_V1
-}
-
-struct FileCryptoMetaData {
-  1: required EncryptionAlgorithm encryption_algorithm
-  
-  /** Parquet footer can be encrypted, or left as plaintext **/
-  2: required bool encrypted_footer
-    
-  /** Retrieval metadata of key used for encryption of footer, 
-   *  and (possibly) columns **/
-  3: optional binary footer_key_metadata
-
-  /** Offset of Parquet footer (encrypted, or plaintext) **/
-  4: required i64 footer_offset
-  
-  /** If file IVs are comprised of a fixed part,
-   *  and variable parts (random or counter), keep the fixed
-   *  part here **/
-  5: optional binary iv_prefix
-}
-
diff --git a/src/parquet/parquet_version.h.in b/src/parquet/parquet_version.h.in
deleted file mode 100644
index db8f396..0000000
--- a/src/parquet/parquet_version.h.in
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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.
-
-#ifndef PARQUET_VERSION_H
-#define PARQUET_VERSION_H
-
-// define the parquet created by version
-#define CREATED_BY_VERSION "parquet-cpp version @PARQUET_VERSION@"
-
-#endif  // PARQUET_VERSION_H
diff --git a/src/parquet/printer.cc b/src/parquet/printer.cc
deleted file mode 100644
index 9f26a41..0000000
--- a/src/parquet/printer.cc
+++ /dev/null
@@ -1,254 +0,0 @@
-// 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.
-
-#include "parquet/printer.h"
-
-#include <string>
-#include <vector>
-
-#include "parquet/column_scanner.h"
-
-using std::string;
-using std::vector;
-
-namespace parquet {
-// ----------------------------------------------------------------------
-// ParquetFilePrinter::DebugPrint
-
-// the fixed initial size is just for an example
-#define COL_WIDTH "30"
-
-void ParquetFilePrinter::DebugPrint(std::ostream& stream, std::list<int> selected_columns,
-                                    bool print_values, bool print_key_value_metadata,
-                                    const char* filename) {
-  const FileMetaData* file_metadata = fileReader->metadata().get();
-
-  stream << "File Name: " << filename << "\n";
-  stream << "Version: " << file_metadata->version() << "\n";
-  stream << "Created By: " << file_metadata->created_by() << "\n";
-  stream << "Total rows: " << file_metadata->num_rows() << "\n";
-
-  if (print_key_value_metadata) {
-    auto key_value_metadata = file_metadata->key_value_metadata();
-    int64_t size_of_key_value_metadata = key_value_metadata->size();
-    stream << "Key Value File Metadata: " << size_of_key_value_metadata << " entries\n";
-    for (int64_t i = 0; i < size_of_key_value_metadata; i++) {
-      stream << " Key nr " << i << " " << key_value_metadata->key(i) << ": "
-             << key_value_metadata->value(i) << "\n";
-    }
-  }
-
-  stream << "Number of RowGroups: " << file_metadata->num_row_groups() << "\n";
-  stream << "Number of Real Columns: "
-         << file_metadata->schema()->group_node()->field_count() << "\n";
-
-  if (selected_columns.size() == 0) {
-    for (int i = 0; i < file_metadata->num_columns(); i++) {
-      selected_columns.push_back(i);
-    }
-  } else {
-    for (auto i : selected_columns) {
-      if (i < 0 || i >= file_metadata->num_columns()) {
-        throw ParquetException("Selected column is out of range");
-      }
-    }
-  }
-
-  stream << "Number of Columns: " << file_metadata->num_columns() << "\n";
-  stream << "Number of Selected Columns: " << selected_columns.size() << "\n";
-  for (auto i : selected_columns) {
-    const ColumnDescriptor* descr = file_metadata->schema()->Column(i);
-    stream << "Column " << i << ": " << descr->name() << " ("
-           << TypeToString(descr->physical_type()) << ")" << std::endl;
-  }
-
-  for (int r = 0; r < file_metadata->num_row_groups(); ++r) {
-    stream << "--- Row Group " << r << " ---\n";
-
-    auto group_reader = fileReader->RowGroup(r);
-    std::unique_ptr<RowGroupMetaData> group_metadata = file_metadata->RowGroup(r);
-
-    stream << "--- Total Bytes " << group_metadata->total_byte_size() << " ---\n";
-    stream << "  Rows: " << group_metadata->num_rows() << "---\n";
-
-    // Print column metadata
-    for (auto i : selected_columns) {
-      auto column_chunk = group_metadata->ColumnChunk(i);
-      std::shared_ptr<RowGroupStatistics> stats = column_chunk->statistics();
-
-      const ColumnDescriptor* descr = file_metadata->schema()->Column(i);
-      stream << "Column " << i << std::endl << ", Values: " << column_chunk->num_values();
-      if (column_chunk->is_stats_set()) {
-        std::string min = stats->EncodeMin(), max = stats->EncodeMax();
-        stream << ", Null Values: " << stats->null_count()
-               << ", Distinct Values: " << stats->distinct_count() << std::endl
-               << "  Max: " << FormatStatValue(descr->physical_type(), max)
-               << ", Min: " << FormatStatValue(descr->physical_type(), min);
-      } else {
-        stream << "  Statistics Not Set";
-      }
-      stream << std::endl
-             << "  Compression: " << CompressionToString(column_chunk->compression())
-             << ", Encodings: ";
-      for (auto encoding : column_chunk->encodings()) {
-        stream << EncodingToString(encoding) << " ";
-      }
-      stream << std::endl
-             << "  Uncompressed Size: " << column_chunk->total_uncompressed_size()
-             << ", Compressed Size: " << column_chunk->total_compressed_size()
-             << std::endl;
-    }
-
-    if (!print_values) {
-      continue;
-    }
-
-    static constexpr int bufsize = 25;
-    char buffer[bufsize];
-
-    // Create readers for selected columns and print contents
-    vector<std::shared_ptr<Scanner>> scanners(selected_columns.size(), nullptr);
-    int j = 0;
-    for (auto i : selected_columns) {
-      std::shared_ptr<ColumnReader> col_reader = group_reader->Column(i);
-
-      std::stringstream ss;
-      ss << "%-" << COL_WIDTH << "s";
-      std::string fmt = ss.str();
-
-      snprintf(buffer, bufsize, fmt.c_str(),
-               file_metadata->schema()->Column(i)->name().c_str());
-      stream << buffer;
-
-      // This is OK in this method as long as the RowGroupReader does not get
-      // deleted
-      scanners[j++] = Scanner::Make(col_reader);
-    }
-    stream << "\n";
-
-    bool hasRow;
-    do {
-      hasRow = false;
-      for (auto scanner : scanners) {
-        if (scanner->HasNext()) {
-          hasRow = true;
-          scanner->PrintNext(stream, 27);
-        }
-      }
-      stream << "\n";
-    } while (hasRow);
-  }
-}
-
-void ParquetFilePrinter::JSONPrint(std::ostream& stream, std::list<int> selected_columns,
-                                   const char* filename) {
-  const FileMetaData* file_metadata = fileReader->metadata().get();
-  stream << "{\n";
-  stream << "  \"FileName\": \"" << filename << "\",\n";
-  stream << "  \"Version\": \"" << file_metadata->version() << "\",\n";
-  stream << "  \"CreatedBy\": \"" << file_metadata->created_by() << "\",\n";
-  stream << "  \"TotalRows\": \"" << file_metadata->num_rows() << "\",\n";
-  stream << "  \"NumberOfRowGroups\": \"" << file_metadata->num_row_groups() << "\",\n";
-  stream << "  \"NumberOfRealColumns\": \""
-         << file_metadata->schema()->group_node()->field_count() << "\",\n";
-  stream << "  \"NumberOfColumns\": \"" << file_metadata->num_columns() << "\",\n";
-
-  if (selected_columns.size() == 0) {
-    for (int i = 0; i < file_metadata->num_columns(); i++) {
-      selected_columns.push_back(i);
-    }
-  } else {
-    for (auto i : selected_columns) {
-      if (i < 0 || i >= file_metadata->num_columns()) {
-        throw ParquetException("Selected column is out of range");
-      }
-    }
-  }
-
-  stream << "  \"Columns\": [\n";
-  int c = 0;
-  for (auto i : selected_columns) {
-    const ColumnDescriptor* descr = file_metadata->schema()->Column(i);
-    stream << "     { \"Id\": \"" << i << "\", \"Name\": \"" << descr->name() << "\","
-           << " \"PhysicalType\": \"" << TypeToString(descr->physical_type()) << "\","
-           << " \"LogicalType\": \"" << LogicalTypeToString(descr->logical_type())
-           << "\" }";
-    c++;
-    if (c != static_cast<int>(selected_columns.size())) {
-      stream << ",\n";
-    }
-  }
-
-  stream << "\n  ],\n  \"RowGroups\": [\n";
-  for (int r = 0; r < file_metadata->num_row_groups(); ++r) {
-    stream << "     {\n       \"Id\": \"" << r << "\", ";
-
-    auto group_reader = fileReader->RowGroup(r);
-    std::unique_ptr<RowGroupMetaData> group_metadata = file_metadata->RowGroup(r);
-
-    stream << " \"TotalBytes\": \"" << group_metadata->total_byte_size() << "\", ";
-    stream << " \"Rows\": \"" << group_metadata->num_rows() << "\",\n";
-
-    // Print column metadata
-    stream << "       \"ColumnChunks\": [\n";
-    int c1 = 0;
-    for (auto i : selected_columns) {
-      auto column_chunk = group_metadata->ColumnChunk(i);
-      std::shared_ptr<RowGroupStatistics> stats = column_chunk->statistics();
-
-      const ColumnDescriptor* descr = file_metadata->schema()->Column(i);
-      stream << "          {\"Id\": \"" << i << "\", \"Values\": \""
-             << column_chunk->num_values() << "\", "
-             << "\"StatsSet\": ";
-      if (column_chunk->is_stats_set()) {
-        stream << "\"True\", \"Stats\": {";
-        std::string min = stats->EncodeMin(), max = stats->EncodeMax();
-        stream << "\"NumNulls\": \"" << stats->null_count() << "\", "
-               << "\"DistinctValues\": \"" << stats->distinct_count() << "\", "
-               << "\"Max\": \"" << FormatStatValue(descr->physical_type(), max) << "\", "
-               << "\"Min\": \"" << FormatStatValue(descr->physical_type(), min)
-               << "\" },";
-      } else {
-        stream << "\"False\",";
-      }
-      stream << "\n           \"Compression\": \""
-             << CompressionToString(column_chunk->compression())
-             << "\", \"Encodings\": \"";
-      for (auto encoding : column_chunk->encodings()) {
-        stream << EncodingToString(encoding) << " ";
-      }
-      stream << "\", "
-             << "\"UncompressedSize\": \"" << column_chunk->total_uncompressed_size()
-             << "\", \"CompressedSize\": \"" << column_chunk->total_compressed_size();
-
-      // end of a ColumnChunk
-      stream << "\" }";
-      c1++;
-      if (c1 != static_cast<int>(selected_columns.size())) {
-        stream << ",\n";
-      }
-    }
-
-    stream << "\n        ]\n     }";
-    if ((r + 1) != static_cast<int>(file_metadata->num_row_groups())) {
-      stream << ",\n";
-    }
-  }
-  stream << "\n  ]\n}\n";
-}
-
-}  // namespace parquet
diff --git a/src/parquet/printer.h b/src/parquet/printer.h
deleted file mode 100644
index 1113c3f..0000000
--- a/src/parquet/printer.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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.
-
-#ifndef PARQUET_FILE_PRINTER_H
-#define PARQUET_FILE_PRINTER_H
-
-#include <cstdint>
-#include <iosfwd>
-#include <list>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "parquet/file_reader.h"
-
-namespace parquet {
-
-class PARQUET_EXPORT ParquetFilePrinter {
- private:
-  ParquetFileReader* fileReader;
-
- public:
-  explicit ParquetFilePrinter(ParquetFileReader* reader) : fileReader(reader) {}
-  ~ParquetFilePrinter() {}
-
-  void DebugPrint(std::ostream& stream, std::list<int> selected_columns,
-                  bool print_values = true, bool print_key_value_metadata = false,
-                  const char* filename = "No Name");
-
-  void JSONPrint(std::ostream& stream, std::list<int> selected_columns,
-                 const char* filename = "No Name");
-};
-
-}  // namespace parquet
-
-#endif  // PARQUET_FILE_PRINTER_H
diff --git a/src/parquet/properties-test.cc b/src/parquet/properties-test.cc
deleted file mode 100644
index c740b59..0000000
--- a/src/parquet/properties-test.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// 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.
-
-#include <gtest/gtest.h>
-
-#include <string>
-
-#include "parquet/file_reader.h"
-#include "parquet/properties.h"
-
-namespace parquet {
-
-using schema::ColumnPath;
-
-namespace test {
-
-TEST(TestReaderProperties, Basics) {
-  ReaderProperties props;
-
-  ASSERT_EQ(DEFAULT_BUFFER_SIZE, props.buffer_size());
-  ASSERT_EQ(DEFAULT_USE_BUFFERED_STREAM, props.is_buffered_stream_enabled());
-}
-
-TEST(TestWriterProperties, Basics) {
-  std::shared_ptr<WriterProperties> props = WriterProperties::Builder().build();
-
-  ASSERT_EQ(DEFAULT_PAGE_SIZE, props->data_pagesize());
-  ASSERT_EQ(DEFAULT_DICTIONARY_PAGE_SIZE_LIMIT, props->dictionary_pagesize_limit());
-  ASSERT_EQ(DEFAULT_WRITER_VERSION, props->version());
-}
-
-TEST(TestWriterProperties, AdvancedHandling) {
-  WriterProperties::Builder builder;
-  builder.compression("gzip", Compression::GZIP);
-  builder.compression("zstd", Compression::ZSTD);
-  builder.compression(Compression::SNAPPY);
-  builder.encoding(Encoding::DELTA_BINARY_PACKED);
-  builder.encoding("delta-length", Encoding::DELTA_LENGTH_BYTE_ARRAY);
-  std::shared_ptr<WriterProperties> props = builder.build();
-
-  ASSERT_EQ(Compression::GZIP, props->compression(ColumnPath::FromDotString("gzip")));
-  ASSERT_EQ(Compression::ZSTD, props->compression(ColumnPath::FromDotString("zstd")));
-  ASSERT_EQ(Compression::SNAPPY,
-            props->compression(ColumnPath::FromDotString("delta-length")));
-  ASSERT_EQ(Encoding::DELTA_BINARY_PACKED,
-            props->encoding(ColumnPath::FromDotString("gzip")));
-  ASSERT_EQ(Encoding::DELTA_LENGTH_BYTE_ARRAY,
-            props->encoding(ColumnPath::FromDotString("delta-length")));
-}
-
-}  // namespace test
-}  // namespace parquet
diff --git a/src/parquet/properties.h b/src/parquet/properties.h
deleted file mode 100644
index 83dc205..0000000
--- a/src/parquet/properties.h
+++ /dev/null
@@ -1,438 +0,0 @@
-// 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.
-
-#ifndef PARQUET_COLUMN_PROPERTIES_H
-#define PARQUET_COLUMN_PROPERTIES_H
-
-#include <memory>
-#include <string>
-#include <unordered_map>
-
-#include "parquet/exception.h"
-#include "parquet/parquet_version.h"
-#include "parquet/schema.h"
-#include "parquet/types.h"
-#include "parquet/util/memory.h"
-#include "parquet/util/visibility.h"
-
-namespace parquet {
-
-struct ParquetVersion {
-  enum type { PARQUET_1_0, PARQUET_2_0 };
-};
-
-static int64_t DEFAULT_BUFFER_SIZE = 0;
-static bool DEFAULT_USE_BUFFERED_STREAM = false;
-
-class PARQUET_EXPORT ReaderProperties {
- public:
-  explicit ReaderProperties(::arrow::MemoryPool* pool = ::arrow::default_memory_pool())
-      : pool_(pool) {
-    buffered_stream_enabled_ = DEFAULT_USE_BUFFERED_STREAM;
-    buffer_size_ = DEFAULT_BUFFER_SIZE;
-  }
-
-  ::arrow::MemoryPool* memory_pool() const { return pool_; }
-
-  std::unique_ptr<InputStream> GetStream(RandomAccessSource* source, int64_t start,
-                                         int64_t num_bytes) {
-    std::unique_ptr<InputStream> stream;
-    if (buffered_stream_enabled_) {
-      stream.reset(
-          new BufferedInputStream(pool_, buffer_size_, source, start, num_bytes));
-    } else {
-      stream.reset(new InMemoryInputStream(source, start, num_bytes));
-    }
-    return stream;
-  }
-
-  bool is_buffered_stream_enabled() const { return buffered_stream_enabled_; }
-
-  void enable_buffered_stream() { buffered_stream_enabled_ = true; }
-
-  void disable_buffered_stream() { buffered_stream_enabled_ = false; }
-
-  void set_buffer_size(int64_t buf_size) { buffer_size_ = buf_size; }
-
-  int64_t buffer_size() const { return buffer_size_; }
-
- private:
-  ::arrow::MemoryPool* pool_;
-  int64_t buffer_size_;
-  bool buffered_stream_enabled_;
-};
-
-ReaderProperties PARQUET_EXPORT default_reader_properties();
-
-static constexpr int64_t DEFAULT_PAGE_SIZE = 1024 * 1024;
-static constexpr bool DEFAULT_IS_DICTIONARY_ENABLED = true;
-static constexpr int64_t DEFAULT_DICTIONARY_PAGE_SIZE_LIMIT = DEFAULT_PAGE_SIZE;
-static constexpr int64_t DEFAULT_WRITE_BATCH_SIZE = 1024;
-static constexpr int64_t DEFAULT_MAX_ROW_GROUP_LENGTH = 64 * 1024 * 1024;
-static constexpr bool DEFAULT_ARE_STATISTICS_ENABLED = true;
-static constexpr int64_t DEFAULT_MAX_STATISTICS_SIZE = 4096;
-static constexpr Encoding::type DEFAULT_ENCODING = Encoding::PLAIN;
-static constexpr ParquetVersion::type DEFAULT_WRITER_VERSION =
-    ParquetVersion::PARQUET_1_0;
-static const char DEFAULT_CREATED_BY[] = CREATED_BY_VERSION;
-static constexpr Compression::type DEFAULT_COMPRESSION_TYPE = Compression::UNCOMPRESSED;
-
-class PARQUET_EXPORT ColumnProperties {
- public:
-  ColumnProperties(Encoding::type encoding = DEFAULT_ENCODING,
-                   Compression::type codec = DEFAULT_COMPRESSION_TYPE,
-                   bool dictionary_enabled = DEFAULT_IS_DICTIONARY_ENABLED,
-                   bool statistics_enabled = DEFAULT_ARE_STATISTICS_ENABLED,
-                   size_t max_stats_size = DEFAULT_MAX_STATISTICS_SIZE)
-      : encoding_(encoding),
-        codec_(codec),
-        dictionary_enabled_(dictionary_enabled),
-        statistics_enabled_(statistics_enabled),
-        max_stats_size_(max_stats_size) {}
-
-  void set_encoding(Encoding::type encoding) { encoding_ = encoding; }
-
-  void set_compression(Compression::type codec) { codec_ = codec; }
-
-  void set_dictionary_enabled(bool dictionary_enabled) {
-    dictionary_enabled_ = dictionary_enabled;
-  }
-
-  void set_statistics_enabled(bool statistics_enabled) {
-    statistics_enabled_ = statistics_enabled;
-  }
-
-  void set_max_statistics_size(size_t max_stats_size) {
-    max_stats_size_ = max_stats_size;
-  }
-
-  Encoding::type encoding() const { return encoding_; }
-
-  Compression::type compression() const { return codec_; }
-
-  bool dictionary_enabled() const { return dictionary_enabled_; }
-
-  bool statistics_enabled() const { return statistics_enabled_; }
-
-  size_t max_statistics_size() const { return max_stats_size_; }
-
- private:
-  Encoding::type encoding_;
-  Compression::type codec_;
-  bool dictionary_enabled_;
-  bool statistics_enabled_;
-  size_t max_stats_size_;
-};
-
-class PARQUET_EXPORT WriterProperties {
- public:
-  class Builder {
-   public:
-    Builder()
-        : pool_(::arrow::default_memory_pool()),
-          dictionary_pagesize_limit_(DEFAULT_DICTIONARY_PAGE_SIZE_LIMIT),
-          write_batch_size_(DEFAULT_WRITE_BATCH_SIZE),
-          max_row_group_length_(DEFAULT_MAX_ROW_GROUP_LENGTH),
-          pagesize_(DEFAULT_PAGE_SIZE),
-          version_(DEFAULT_WRITER_VERSION),
-          created_by_(DEFAULT_CREATED_BY) {}
-    virtual ~Builder() {}
-
-    Builder* memory_pool(::arrow::MemoryPool* pool) {
-      pool_ = pool;
-      return this;
-    }
-
-    Builder* enable_dictionary() {
-      default_column_properties_.set_dictionary_enabled(true);
-      return this;
-    }
-
-    Builder* disable_dictionary() {
-      default_column_properties_.set_dictionary_enabled(false);
-      return this;
-    }
-
-    Builder* enable_dictionary(const std::string& path) {
-      dictionary_enabled_[path] = true;
-      return this;
-    }
-
-    Builder* enable_dictionary(const std::shared_ptr<schema::ColumnPath>& path) {
-      return this->enable_dictionary(path->ToDotString());
-    }
-
-    Builder* disable_dictionary(const std::string& path) {
-      dictionary_enabled_[path] = false;
-      return this;
-    }
-
-    Builder* disable_dictionary(const std::shared_ptr<schema::ColumnPath>& path) {
-      return this->disable_dictionary(path->ToDotString());
-    }
-
-    Builder* dictionary_pagesize_limit(int64_t dictionary_psize_limit) {
-      dictionary_pagesize_limit_ = dictionary_psize_limit;
-      return this;
-    }
-
-    Builder* write_batch_size(int64_t write_batch_size) {
-      write_batch_size_ = write_batch_size;
-      return this;
-    }
-
-    Builder* max_row_group_length(int64_t max_row_group_length) {
-      max_row_group_length_ = max_row_group_length;
-      return this;
-    }
-
-    Builder* data_pagesize(int64_t pg_size) {
-      pagesize_ = pg_size;
-      return this;
-    }
-
-    Builder* version(ParquetVersion::type version) {
-      version_ = version;
-      return this;
-    }
-
-    Builder* created_by(const std::string& created_by) {
-      created_by_ = created_by;
-      return this;
-    }
-
-    /**
-     * Define the encoding that is used when we don't utilise dictionary encoding.
-     *
-     * This either apply if dictionary encoding is disabled or if we fallback
-     * as the dictionary grew too large.
-     */
-    Builder* encoding(Encoding::type encoding_type) {
-      if (encoding_type == Encoding::PLAIN_DICTIONARY ||
-          encoding_type == Encoding::RLE_DICTIONARY) {
-        throw ParquetException("Can't use dictionary encoding as fallback encoding");
-      }
-
-      default_column_properties_.set_encoding(encoding_type);
-      return this;
-    }
-
-    /**
-     * Define the encoding that is used when we don't utilise dictionary encoding.
-     *
-     * This either apply if dictionary encoding is disabled or if we fallback
-     * as the dictionary grew too large.
-     */
-    Builder* encoding(const std::string& path, Encoding::type encoding_type) {
-      if (encoding_type == Encoding::PLAIN_DICTIONARY ||
-          encoding_type == Encoding::RLE_DICTIONARY) {
-        throw ParquetException("Can't use dictionary encoding as fallback encoding");
-      }
-
-      encodings_[path] = encoding_type;
-      return this;
-    }
-
-    /**
-     * Define the encoding that is used when we don't utilise dictionary encoding.
-     *
-     * This either apply if dictionary encoding is disabled or if we fallback
-     * as the dictionary grew too large.
-     */
-    Builder* encoding(const std::shared_ptr<schema::ColumnPath>& path,
-                      Encoding::type encoding_type) {
-      return this->encoding(path->ToDotString(), encoding_type);
-    }
-
-    Builder* compression(Compression::type codec) {
-      default_column_properties_.set_compression(codec);
-      return this;
-    }
-
-    Builder* max_statistics_size(size_t max_stats_sz) {
-      default_column_properties_.set_max_statistics_size(max_stats_sz);
-      return this;
-    }
-
-    Builder* compression(const std::string& path, Compression::type codec) {
-      codecs_[path] = codec;
-      return this;
-    }
-
-    Builder* compression(const std::shared_ptr<schema::ColumnPath>& path,
-                         Compression::type codec) {
-      return this->compression(path->ToDotString(), codec);
-    }
-
-    Builder* enable_statistics() {
-      default_column_properties_.set_statistics_enabled(true);
-      return this;
-    }
-
-    Builder* disable_statistics() {
-      default_column_properties_.set_statistics_enabled(false);
-      return this;
-    }
-
-    Builder* enable_statistics(const std::string& path) {
-      statistics_enabled_[path] = true;
-      return this;
-    }
-
-    Builder* enable_statistics(const std::shared_ptr<schema::ColumnPath>& path) {
-      return this->enable_statistics(path->ToDotString());
-    }
-
-    Builder* disable_statistics(const std::string& path) {
-      statistics_enabled_[path] = false;
-      return this;
-    }
-
-    Builder* disable_statistics(const std::shared_ptr<schema::ColumnPath>& path) {
-      return this->disable_statistics(path->ToDotString());
-    }
-
-    std::shared_ptr<WriterProperties> build() {
-      std::unordered_map<std::string, ColumnProperties> column_properties;
-      auto get = [&](const std::string& key) -> ColumnProperties& {
-        auto it = column_properties.find(key);
-        if (it == column_properties.end())
-          return column_properties[key] = default_column_properties_;
-        else
-          return it->second;
-      };
-
-      for (const auto& item : encodings_) get(item.first).set_encoding(item.second);
-      for (const auto& item : codecs_) get(item.first).set_compression(item.second);
-      for (const auto& item : dictionary_enabled_)
-        get(item.first).set_dictionary_enabled(item.second);
-      for (const auto& item : statistics_enabled_)
-        get(item.first).set_statistics_enabled(item.second);
-
-      return std::shared_ptr<WriterProperties>(
-          new WriterProperties(pool_, dictionary_pagesize_limit_, write_batch_size_,
-                               max_row_group_length_, pagesize_, version_, created_by_,
-                               default_column_properties_, column_properties));
-    }
-
-   private:
-    ::arrow::MemoryPool* pool_;
-    int64_t dictionary_pagesize_limit_;
-    int64_t write_batch_size_;
-    int64_t max_row_group_length_;
-    int64_t pagesize_;
-    ParquetVersion::type version_;
-    std::string created_by_;
-
-    // Settings used for each column unless overridden in any of the maps below
-    ColumnProperties default_column_properties_;
-    std::unordered_map<std::string, Encoding::type> encodings_;
-    std::unordered_map<std::string, Compression::type> codecs_;
-    std::unordered_map<std::string, bool> dictionary_enabled_;
-    std::unordered_map<std::string, bool> statistics_enabled_;
-  };
-
-  inline ::arrow::MemoryPool* memory_pool() const { return pool_; }
-
-  inline int64_t dictionary_pagesize_limit() const { return dictionary_pagesize_limit_; }
-
-  inline int64_t write_batch_size() const { return write_batch_size_; }
-
-  inline int64_t max_row_group_length() const { return max_row_group_length_; }
-
-  inline int64_t data_pagesize() const { return pagesize_; }
-
-  inline ParquetVersion::type version() const { return parquet_version_; }
-
-  inline std::string created_by() const { return parquet_created_by_; }
-
-  inline Encoding::type dictionary_index_encoding() const {
-    if (parquet_version_ == ParquetVersion::PARQUET_1_0) {
-      return Encoding::PLAIN_DICTIONARY;
-    } else {
-      return Encoding::RLE_DICTIONARY;
-    }
-  }
-
-  inline Encoding::type dictionary_page_encoding() const {
-    if (parquet_version_ == ParquetVersion::PARQUET_1_0) {
-      return Encoding::PLAIN_DICTIONARY;
-    } else {
-      return Encoding::PLAIN;
-    }
-  }
-
-  const ColumnProperties& column_properties(
-      const std::shared_ptr<schema::ColumnPath>& path) const {
-    auto it = column_properties_.find(path->ToDotString());
-    if (it != column_properties_.end()) return it->second;
-    return default_column_properties_;
-  }
-
-  Encoding::type encoding(const std::shared_ptr<schema::ColumnPath>& path) const {
-    return column_properties(path).encoding();
-  }
-
-  Compression::type compression(const std::shared_ptr<schema::ColumnPath>& path) const {
-    return column_properties(path).compression();
-  }
-
-  bool dictionary_enabled(const std::shared_ptr<schema::ColumnPath>& path) const {
-    return column_properties(path).dictionary_enabled();
-  }
-
-  bool statistics_enabled(const std::shared_ptr<schema::ColumnPath>& path) const {
-    return column_properties(path).statistics_enabled();
-  }
-
-  size_t max_statistics_size(const std::shared_ptr<schema::ColumnPath>& path) const {
-    return column_properties(path).max_statistics_size();
-  }
-
- private:
-  explicit WriterProperties(
-      ::arrow::MemoryPool* pool, int64_t dictionary_pagesize_limit,
-      int64_t write_batch_size, int64_t max_row_group_length, int64_t pagesize,
-      ParquetVersion::type version, const std::string& created_by,
-      const ColumnProperties& default_column_properties,
-      const std::unordered_map<std::string, ColumnProperties>& column_properties)
-      : pool_(pool),
-        dictionary_pagesize_limit_(dictionary_pagesize_limit),
-        write_batch_size_(write_batch_size),
-        max_row_group_length_(max_row_group_length),
-        pagesize_(pagesize),
-        parquet_version_(version),
-        parquet_created_by_(created_by),
-        default_column_properties_(default_column_properties),
-        column_properties_(column_properties) {}
-
-  ::arrow::MemoryPool* pool_;
-  int64_t dictionary_pagesize_limit_;
-  int64_t write_batch_size_;
-  int64_t max_row_group_length_;
-  int64_t pagesize_;
-  ParquetVersion::type parquet_version_;
-  std::string parquet_created_by_;
-  ColumnProperties default_column_properties_;
-  std::unordered_map<std::string, ColumnProperties> column_properties_;
-};
-
-std::shared_ptr<WriterProperties> PARQUET_EXPORT default_writer_properties();
-
-}  // namespace parquet
-
-#endif  // PARQUET_COLUMN_PROPERTIES_H
diff --git a/src/parquet/public-api-test.cc b/src/parquet/public-api-test.cc
deleted file mode 100644
index 958e970..0000000
--- a/src/parquet/public-api-test.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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.
-
-#include <gtest/gtest.h>
-
-#include "parquet/api/io.h"
-#include "parquet/api/reader.h"
-#include "parquet/api/schema.h"
-#include "parquet/api/writer.h"
-
-TEST(TestPublicAPI, DoesNotIncludeThrift) {
-#ifdef _THRIFT_THRIFT_H_
-  FAIL() << "Thrift headers should not be in the public API";
-#endif
-}
-
-TEST(TestPublicAPI, DoesNotExportDCHECK) {
-#ifdef DCHECK
-  FAIL() << "parquet/util/logging.h should not be transitively included";
-#endif
-}
-
-TEST(TestPublicAPI, DoesNotIncludeZlib) {
-#ifdef ZLIB_H
-  FAIL() << "zlib.h should not be transitively included";
-#endif
-}
-
-PARQUET_NORETURN void ThrowsParquetException() {
-  throw parquet::ParquetException("This function throws");
-}
-
-TEST(TestPublicAPI, CanThrowParquetException) {
-  ASSERT_THROW(ThrowsParquetException(), parquet::ParquetException);
-}
diff --git a/src/parquet/reader-test.cc b/src/parquet/reader-test.cc
deleted file mode 100644
index d628f47..0000000
--- a/src/parquet/reader-test.cc
+++ /dev/null
@@ -1,325 +0,0 @@
-// 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.
-
-#include <fcntl.h>
-#include <gtest/gtest.h>
-#include <cstdint>
-#include <cstdlib>
-#include <iostream>
-#include <memory>
-#include <string>
-
-#include "arrow/io/file.h"
-
-#include "parquet/column_reader.h"
-#include "parquet/column_scanner.h"
-#include "parquet/file_reader.h"
-#include "parquet/printer.h"
-#include "parquet/util/memory.h"
-#include "parquet/util/test-common.h"
-
-using std::string;
-
-namespace parquet {
-
-using ReadableFile = ::arrow::io::ReadableFile;
-
-std::string alltypes_plain() {
-  std::string dir_string(test::get_data_dir());
-  std::stringstream ss;
-  ss << dir_string << "/"
-     << "alltypes_plain.parquet";
-  return ss.str();
-}
-
-std::string nation_dict_truncated_data_page() {
-  std::string dir_string(test::get_data_dir());
-  std::stringstream ss;
-  ss << dir_string << "/"
-     << "nation.dict-malformed.parquet";
-  return ss.str();
-}
-
-class TestAllTypesPlain : public ::testing::Test {
- public:
-  void SetUp() { reader_ = ParquetFileReader::OpenFile(alltypes_plain()); }
-
-  void TearDown() {}
-
- protected:
-  std::unique_ptr<ParquetFileReader> reader_;
-};
-
-TEST_F(TestAllTypesPlain, NoopConstructDestruct) {}
-
-TEST_F(TestAllTypesPlain, TestBatchRead) {
-  std::shared_ptr<RowGroupReader> group = reader_->RowGroup(0);
-
-  // column 0, id
-  std::shared_ptr<Int32Reader> col =
-      std::dynamic_pointer_cast<Int32Reader>(group->Column(0));
-
-  int16_t def_levels[4];
-  int16_t rep_levels[4];
-  int32_t values[4];
-
-  // This file only has 8 rows
-  ASSERT_EQ(8, reader_->metadata()->num_rows());
-  // This file only has 1 row group
-  ASSERT_EQ(1, reader_->metadata()->num_row_groups());
-  // Size of the metadata is 730 bytes
-  ASSERT_EQ(730, reader_->metadata()->size());
-  // This row group must have 8 rows
-  ASSERT_EQ(8, group->metadata()->num_rows());
-
-  ASSERT_TRUE(col->HasNext());
-  int64_t values_read;
-  auto levels_read = col->ReadBatch(4, def_levels, rep_levels, values, &values_read);
-  ASSERT_EQ(4, levels_read);
-  ASSERT_EQ(4, values_read);
-
-  // Now read past the end of the file
-  ASSERT_TRUE(col->HasNext());
-  levels_read = col->ReadBatch(5, def_levels, rep_levels, values, &values_read);
-  ASSERT_EQ(4, levels_read);
-  ASSERT_EQ(4, values_read);
-
-  ASSERT_FALSE(col->HasNext());
-}
-
-TEST_F(TestAllTypesPlain, TestFlatScannerInt32) {
-  std::shared_ptr<RowGroupReader> group = reader_->RowGroup(0);
-
-  // column 0, id
-  std::shared_ptr<Int32Scanner> scanner(new Int32Scanner(group->Column(0)));
-  int32_t val;
-  bool is_null;
-  for (int i = 0; i < 8; ++i) {
-    ASSERT_TRUE(scanner->HasNext());
-    ASSERT_TRUE(scanner->NextValue(&val, &is_null));
-    ASSERT_FALSE(is_null);
-  }
-  ASSERT_FALSE(scanner->HasNext());
-  ASSERT_FALSE(scanner->NextValue(&val, &is_null));
-}
-
-TEST_F(TestAllTypesPlain, TestSetScannerBatchSize) {
-  std::shared_ptr<RowGroupReader> group = reader_->RowGroup(0);
-
-  // column 0, id
-  std::shared_ptr<Int32Scanner> scanner(new Int32Scanner(group->Column(0)));
-
-  ASSERT_EQ(128, scanner->batch_size());
-  scanner->SetBatchSize(1024);
-  ASSERT_EQ(1024, scanner->batch_size());
-}
-
-TEST_F(TestAllTypesPlain, DebugPrintWorks) {
-  std::stringstream ss;
-
-  std::list<int> columns;
-  ParquetFilePrinter printer(reader_.get());
-  printer.DebugPrint(ss, columns);
-
-  std::string result = ss.str();
-  ASSERT_GT(result.size(), 0);
-}
-
-TEST_F(TestAllTypesPlain, ColumnSelection) {
-  std::stringstream ss;
-
-  std::list<int> columns;
-  columns.push_back(5);
-  columns.push_back(0);
-  columns.push_back(10);
-  ParquetFilePrinter printer(reader_.get());
-  printer.DebugPrint(ss, columns);
-
-  std::string result = ss.str();
-  ASSERT_GT(result.size(), 0);
-}
-
-TEST_F(TestAllTypesPlain, ColumnSelectionOutOfRange) {
-  std::stringstream ss;
-
-  std::list<int> columns;
-  columns.push_back(100);
-  ParquetFilePrinter printer1(reader_.get());
-  ASSERT_THROW(printer1.DebugPrint(ss, columns), ParquetException);
-
-  columns.clear();
-  columns.push_back(-1);
-  ParquetFilePrinter printer2(reader_.get());
-  ASSERT_THROW(printer2.DebugPrint(ss, columns), ParquetException);
-}
-
-class TestLocalFile : public ::testing::Test {
- public:
-  void SetUp() {
-    std::string dir_string(test::get_data_dir());
-
-    std::stringstream ss;
-    ss << dir_string << "/"
-       << "alltypes_plain.parquet";
-
-    PARQUET_THROW_NOT_OK(ReadableFile::Open(ss.str(), &handle));
-    fileno = handle->file_descriptor();
-  }
-
-  void TearDown() {}
-
- protected:
-  int fileno;
-  std::shared_ptr<::arrow::io::ReadableFile> handle;
-};
-
-class HelperFileClosed : public ArrowInputFile {
- public:
-  explicit HelperFileClosed(
-      const std::shared_ptr<::arrow::io::ReadableFileInterface>& file, bool* close_called)
-      : ArrowInputFile(file), close_called_(close_called) {}
-
-  void Close() override { *close_called_ = true; }
-
- private:
-  bool* close_called_;
-};
-
-TEST_F(TestLocalFile, FileClosedOnDestruction) {
-  bool close_called = false;
-  {
-    auto contents = ParquetFileReader::Contents::Open(
-        std::unique_ptr<RandomAccessSource>(new HelperFileClosed(handle, &close_called)));
-    std::unique_ptr<ParquetFileReader> result(new ParquetFileReader());
-    result->Open(std::move(contents));
-  }
-  ASSERT_TRUE(close_called);
-}
-
-TEST_F(TestLocalFile, OpenWithMetadata) {
-  // PARQUET-808
-  std::stringstream ss;
-  std::shared_ptr<FileMetaData> metadata = ReadMetaData(handle);
-
-  auto reader = ParquetFileReader::Open(handle, default_reader_properties(), metadata);
-
-  // Compare pointers
-  ASSERT_EQ(metadata.get(), reader->metadata().get());
-
-  std::list<int> columns;
-  ParquetFilePrinter printer(reader.get());
-  printer.DebugPrint(ss, columns, true);
-
-  // Make sure OpenFile passes on the external metadata, too
-  auto reader2 = ParquetFileReader::OpenFile(alltypes_plain(), false,
-                                             default_reader_properties(), metadata);
-
-  // Compare pointers
-  ASSERT_EQ(metadata.get(), reader2->metadata().get());
-}
-
-TEST(TestFileReaderAdHoc, NationDictTruncatedDataPage) {
-  // PARQUET-816. Some files generated by older Parquet implementations may
-  // contain malformed data page metadata, and we can successfully decode them
-  // if we optimistically proceed to decoding, even if there is not enough data
-  // available in the stream. Before, we had quite aggressive checking of
-  // stream reads, which are not found e.g. in Impala's Parquet implementation
-  auto reader = ParquetFileReader::OpenFile(nation_dict_truncated_data_page(), false);
-  std::stringstream ss;
-
-  // empty list means print all
-  std::list<int> columns;
-  ParquetFilePrinter printer1(reader.get());
-  printer1.DebugPrint(ss, columns, true);
-
-  reader = ParquetFileReader::OpenFile(nation_dict_truncated_data_page(), true);
-  std::stringstream ss2;
-  ParquetFilePrinter printer2(reader.get());
-  printer2.DebugPrint(ss2, columns, true);
-
-  // The memory-mapped reads runs over the end of the column chunk and succeeds
-  // by accident
-  ASSERT_EQ(ss2.str(), ss.str());
-}
-
-TEST(TestJSONWithLocalFile, JSONOutput) {
-  std::string jsonOutput = R"###({
-  "FileName": "alltypes_plain.parquet",
-  "Version": "0",
-  "CreatedBy": "impala version 1.3.0-INTERNAL (build 8a48ddb1eff84592b3fc06bc6f51ec120e1fffc9)",
-  "TotalRows": "8",
-  "NumberOfRowGroups": "1",
-  "NumberOfRealColumns": "11",
-  "NumberOfColumns": "11",
-  "Columns": [
-     { "Id": "0", "Name": "id", "PhysicalType": "INT32", "LogicalType": "NONE" },
-     { "Id": "1", "Name": "bool_col", "PhysicalType": "BOOLEAN", "LogicalType": "NONE" },
-     { "Id": "2", "Name": "tinyint_col", "PhysicalType": "INT32", "LogicalType": "NONE" },
-     { "Id": "3", "Name": "smallint_col", "PhysicalType": "INT32", "LogicalType": "NONE" },
-     { "Id": "4", "Name": "int_col", "PhysicalType": "INT32", "LogicalType": "NONE" },
-     { "Id": "5", "Name": "bigint_col", "PhysicalType": "INT64", "LogicalType": "NONE" },
-     { "Id": "6", "Name": "float_col", "PhysicalType": "FLOAT", "LogicalType": "NONE" },
-     { "Id": "7", "Name": "double_col", "PhysicalType": "DOUBLE", "LogicalType": "NONE" },
-     { "Id": "8", "Name": "date_string_col", "PhysicalType": "BYTE_ARRAY", "LogicalType": "NONE" },
-     { "Id": "9", "Name": "string_col", "PhysicalType": "BYTE_ARRAY", "LogicalType": "NONE" },
-     { "Id": "10", "Name": "timestamp_col", "PhysicalType": "INT96", "LogicalType": "NONE" }
-  ],
-  "RowGroups": [
-     {
-       "Id": "0",  "TotalBytes": "671",  "Rows": "8",
-       "ColumnChunks": [
-          {"Id": "0", "Values": "8", "StatsSet": "False",
-           "Compression": "UNCOMPRESSED", "Encodings": "RLE PLAIN_DICTIONARY PLAIN ", "UncompressedSize": "73", "CompressedSize": "73" },
-          {"Id": "1", "Values": "8", "StatsSet": "False",
-           "Compression": "UNCOMPRESSED", "Encodings": "RLE PLAIN_DICTIONARY PLAIN ", "UncompressedSize": "24", "CompressedSize": "24" },
-          {"Id": "2", "Values": "8", "StatsSet": "False",
-           "Compression": "UNCOMPRESSED", "Encodings": "RLE PLAIN_DICTIONARY PLAIN ", "UncompressedSize": "47", "CompressedSize": "47" },
-          {"Id": "3", "Values": "8", "StatsSet": "False",
-           "Compression": "UNCOMPRESSED", "Encodings": "RLE PLAIN_DICTIONARY PLAIN ", "UncompressedSize": "47", "CompressedSize": "47" },
-          {"Id": "4", "Values": "8", "StatsSet": "False",
-           "Compression": "UNCOMPRESSED", "Encodings": "RLE PLAIN_DICTIONARY PLAIN ", "UncompressedSize": "47", "CompressedSize": "47" },
-          {"Id": "5", "Values": "8", "StatsSet": "False",
-           "Compression": "UNCOMPRESSED", "Encodings": "RLE PLAIN_DICTIONARY PLAIN ", "UncompressedSize": "55", "CompressedSize": "55" },
-          {"Id": "6", "Values": "8", "StatsSet": "False",
-           "Compression": "UNCOMPRESSED", "Encodings": "RLE PLAIN_DICTIONARY PLAIN ", "UncompressedSize": "47", "CompressedSize": "47" },
-          {"Id": "7", "Values": "8", "StatsSet": "False",
-           "Compression": "UNCOMPRESSED", "Encodings": "RLE PLAIN_DICTIONARY PLAIN ", "UncompressedSize": "55", "CompressedSize": "55" },
-          {"Id": "8", "Values": "8", "StatsSet": "False",
-           "Compression": "UNCOMPRESSED", "Encodings": "RLE PLAIN_DICTIONARY PLAIN ", "UncompressedSize": "88", "CompressedSize": "88" },
-          {"Id": "9", "Values": "8", "StatsSet": "False",
-           "Compression": "UNCOMPRESSED", "Encodings": "RLE PLAIN_DICTIONARY PLAIN ", "UncompressedSize": "49", "CompressedSize": "49" },
-          {"Id": "10", "Values": "8", "StatsSet": "False",
-           "Compression": "UNCOMPRESSED", "Encodings": "RLE PLAIN_DICTIONARY PLAIN ", "UncompressedSize": "139", "CompressedSize": "139" }
-        ]
-     }
-  ]
-}
-)###";
-
-  std::stringstream ss;
-  // empty list means print all
-  std::list<int> columns;
-
-  auto reader =
-      ParquetFileReader::OpenFile(alltypes_plain(), false, default_reader_properties());
-  ParquetFilePrinter printer(reader.get());
-  printer.JSONPrint(ss, columns, "alltypes_plain.parquet");
-
-  ASSERT_EQ(jsonOutput, ss.str());
-}
-
-}  // namespace parquet
diff --git a/src/parquet/schema-internal.h b/src/parquet/schema-internal.h
deleted file mode 100644
index 53472ab..0000000
--- a/src/parquet/schema-internal.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// 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.
-
-// This module contains the logical parquet-cpp types (independent of Thrift
-// structures), schema nodes, and related type tools
-
-#ifndef PARQUET_SCHEMA_INTERNAL_H
-#define PARQUET_SCHEMA_INTERNAL_H
-
-#include <cstdint>
-#include <memory>
-#include <vector>
-
-#include "parquet/parquet_types.h"
-#include "parquet/schema.h"
-#include "parquet/types.h"
-#include "parquet/util/macros.h"
-#include "parquet/util/visibility.h"
-
-namespace parquet {
-namespace schema {
-
-// ----------------------------------------------------------------------
-// Conversion from Parquet Thrift metadata
-
-std::shared_ptr<SchemaDescriptor> FromParquet(
-    const std::vector<format::SchemaElement>& schema);
-
-class FlatSchemaConverter {
- public:
-  FlatSchemaConverter(const format::SchemaElement* elements, int length)
-      : elements_(elements), length_(length), pos_(0), current_id_(0) {}
-
-  std::unique_ptr<Node> Convert();
-
- private:
-  const format::SchemaElement* elements_;
-  int length_;
-  int pos_;
-  int current_id_;
-
-  int next_id() { return current_id_++; }
-
-  const format::SchemaElement& Next();
-
-  std::unique_ptr<Node> NextNode();
-};
-
-// ----------------------------------------------------------------------
-// Conversion to Parquet Thrift metadata
-
-void ToParquet(const GroupNode* schema, std::vector<format::SchemaElement>* out);
-
-// Converts nested parquet schema back to a flat vector of Thrift structs
-class SchemaFlattener {
- public:
-  SchemaFlattener(const GroupNode* schema, std::vector<format::SchemaElement>* out);
-
-  void Flatten();
-
- private:
-  const GroupNode* root_;
-  std::vector<format::SchemaElement>* elements_;
-};
-
-}  // namespace schema
-}  // namespace parquet
-
-#endif  // PARQUET_SCHEMA_INTERNAL_H
diff --git a/src/parquet/schema-test.cc b/src/parquet/schema-test.cc
deleted file mode 100644
index a734a92..0000000
--- a/src/parquet/schema-test.cc
+++ /dev/null
@@ -1,761 +0,0 @@
-// 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.
-
-#include <gtest/gtest.h>
-
-#include <cstdlib>
-#include <iosfwd>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "parquet/exception.h"
-#include "parquet/parquet_types.h"
-#include "parquet/schema-internal.h"
-#include "parquet/schema.h"
-#include "parquet/types.h"
-
-using std::string;
-using std::vector;
-
-namespace parquet {
-
-using format::ConvertedType;
-using format::FieldRepetitionType;
-using format::SchemaElement;
-
-namespace schema {
-
-static inline SchemaElement NewPrimitive(const std::string& name,
-                                         FieldRepetitionType::type repetition,
-                                         format::Type::type type, int id = 0) {
-  SchemaElement result;
-  result.__set_name(name);
-  result.__set_repetition_type(repetition);
-  result.__set_type(type);
-
-  return result;
-}
-
-static inline SchemaElement NewGroup(const std::string& name,
-                                     FieldRepetitionType::type repetition,
-                                     int num_children, int id = 0) {
-  SchemaElement result;
-  result.__set_name(name);
-  result.__set_repetition_type(repetition);
-  result.__set_num_children(num_children);
-
-  return result;
-}
-
-// ----------------------------------------------------------------------
-// ColumnPath
-
-TEST(TestColumnPath, TestAttrs) {
-  ColumnPath path(std::vector<std::string>({"toplevel", "leaf"}));
-
-  ASSERT_EQ(path.ToDotString(), "toplevel.leaf");
-
-  std::shared_ptr<ColumnPath> path_ptr = ColumnPath::FromDotString("toplevel.leaf");
-  ASSERT_EQ(path_ptr->ToDotString(), "toplevel.leaf");
-
-  std::shared_ptr<ColumnPath> extended = path_ptr->extend("anotherlevel");
-  ASSERT_EQ(extended->ToDotString(), "toplevel.leaf.anotherlevel");
-}
-
-// ----------------------------------------------------------------------
-// Primitive node
-
-class TestPrimitiveNode : public ::testing::Test {
- public:
-  void SetUp() {
-    name_ = "name";
-    id_ = 5;
-  }
-
-  void Convert(const format::SchemaElement* element) {
-    node_ = PrimitiveNode::FromParquet(element, id_);
-    ASSERT_TRUE(node_->is_primitive());
-    prim_node_ = static_cast<const PrimitiveNode*>(node_.get());
-  }
-
- protected:
-  std::string name_;
-  const PrimitiveNode* prim_node_;
-
-  int id_;
-  std::unique_ptr<Node> node_;
-};
-
-TEST_F(TestPrimitiveNode, Attrs) {
-  PrimitiveNode node1("foo", Repetition::REPEATED, Type::INT32);
-
-  PrimitiveNode node2("bar", Repetition::OPTIONAL, Type::BYTE_ARRAY, LogicalType::UTF8);
-
-  ASSERT_EQ("foo", node1.name());
-
-  ASSERT_TRUE(node1.is_primitive());
-  ASSERT_FALSE(node1.is_group());
-
-  ASSERT_EQ(Repetition::REPEATED, node1.repetition());
-  ASSERT_EQ(Repetition::OPTIONAL, node2.repetition());
-
-  ASSERT_EQ(Node::PRIMITIVE, node1.node_type());
-
-  ASSERT_EQ(Type::INT32, node1.physical_type());
-  ASSERT_EQ(Type::BYTE_ARRAY, node2.physical_type());
-
-  // logical types
-  ASSERT_EQ(LogicalType::NONE, node1.logical_type());
-  ASSERT_EQ(LogicalType::UTF8, node2.logical_type());
-
-  // repetition
-  PrimitiveNode node3("foo", Repetition::REPEATED, Type::INT32);
-  PrimitiveNode node4("foo", Repetition::REQUIRED, Type::INT32);
-  PrimitiveNode node5("foo", Repetition::OPTIONAL, Type::INT32);
-
-  ASSERT_TRUE(node3.is_repeated());
-  ASSERT_FALSE(node3.is_optional());
-
-  ASSERT_TRUE(node4.is_required());
-
-  ASSERT_TRUE(node5.is_optional());
-  ASSERT_FALSE(node5.is_required());
-}
-
-TEST_F(TestPrimitiveNode, FromParquet) {
-  SchemaElement elt =
-      NewPrimitive(name_, FieldRepetitionType::OPTIONAL, format::Type::INT32, 0);
-  ASSERT_NO_FATAL_FAILURE(Convert(&elt));
-  ASSERT_EQ(name_, prim_node_->name());
-  ASSERT_EQ(id_, prim_node_->id());
-  ASSERT_EQ(Repetition::OPTIONAL, prim_node_->repetition());
-  ASSERT_EQ(Type::INT32, prim_node_->physical_type());
-  ASSERT_EQ(LogicalType::NONE, prim_node_->logical_type());
-
-  // Test a logical type
-  elt = NewPrimitive(name_, FieldRepetitionType::REQUIRED, format::Type::BYTE_ARRAY, 0);
-  elt.__set_converted_type(ConvertedType::UTF8);
-
-  ASSERT_NO_FATAL_FAILURE(Convert(&elt));
-  ASSERT_EQ(Repetition::REQUIRED, prim_node_->repetition());
-  ASSERT_EQ(Type::BYTE_ARRAY, prim_node_->physical_type());
-  ASSERT_EQ(LogicalType::UTF8, prim_node_->logical_type());
-
-  // FIXED_LEN_BYTE_ARRAY
-  elt = NewPrimitive(name_, FieldRepetitionType::OPTIONAL,
-                     format::Type::FIXED_LEN_BYTE_ARRAY, 0);
-  elt.__set_type_length(16);
-
-  ASSERT_NO_FATAL_FAILURE(Convert(&elt));
-  ASSERT_EQ(name_, prim_node_->name());
-  ASSERT_EQ(id_, prim_node_->id());
-  ASSERT_EQ(Repetition::OPTIONAL, prim_node_->repetition());
-  ASSERT_EQ(Type::FIXED_LEN_BYTE_ARRAY, prim_node_->physical_type());
-  ASSERT_EQ(16, prim_node_->type_length());
-
-  // ConvertedType::Decimal
-  elt = NewPrimitive(name_, FieldRepetitionType::OPTIONAL,
-                     format::Type::FIXED_LEN_BYTE_ARRAY, 0);
-  elt.__set_converted_type(ConvertedType::DECIMAL);
-  elt.__set_type_length(6);
-  elt.__set_scale(2);
-  elt.__set_precision(12);
-
-  ASSERT_NO_FATAL_FAILURE(Convert(&elt));
-  ASSERT_EQ(Type::FIXED_LEN_BYTE_ARRAY, prim_node_->physical_type());
-  ASSERT_EQ(LogicalType::DECIMAL, prim_node_->logical_type());
-  ASSERT_EQ(6, prim_node_->type_length());
-  ASSERT_EQ(2, prim_node_->decimal_metadata().scale);
-  ASSERT_EQ(12, prim_node_->decimal_metadata().precision);
-}
-
-TEST_F(TestPrimitiveNode, Equals) {
-  PrimitiveNode node1("foo", Repetition::REQUIRED, Type::INT32);
-  PrimitiveNode node2("foo", Repetition::REQUIRED, Type::INT64);
-  PrimitiveNode node3("bar", Repetition::REQUIRED, Type::INT32);
-  PrimitiveNode node4("foo", Repetition::OPTIONAL, Type::INT32);
-  PrimitiveNode node5("foo", Repetition::REQUIRED, Type::INT32);
-
-  ASSERT_TRUE(node1.Equals(&node1));
-  ASSERT_FALSE(node1.Equals(&node2));
-  ASSERT_FALSE(node1.Equals(&node3));
-  ASSERT_FALSE(node1.Equals(&node4));
-  ASSERT_TRUE(node1.Equals(&node5));
-
-  PrimitiveNode flba1("foo", Repetition::REQUIRED, Type::FIXED_LEN_BYTE_ARRAY,
-                      LogicalType::DECIMAL, 12, 4, 2);
-
-  PrimitiveNode flba2("foo", Repetition::REQUIRED, Type::FIXED_LEN_BYTE_ARRAY,
-                      LogicalType::DECIMAL, 1, 4, 2);
-  flba2.SetTypeLength(12);
-
-  PrimitiveNode flba3("foo", Repetition::REQUIRED, Type::FIXED_LEN_BYTE_ARRAY,
-                      LogicalType::DECIMAL, 1, 4, 2);
-  flba3.SetTypeLength(16);
-
-  PrimitiveNode flba4("foo", Repetition::REQUIRED, Type::FIXED_LEN_BYTE_ARRAY,
-                      LogicalType::DECIMAL, 12, 4, 0);
-
-  PrimitiveNode flba5("foo", Repetition::REQUIRED, Type::FIXED_LEN_BYTE_ARRAY,
-                      LogicalType::NONE, 12, 4, 0);
-
-  ASSERT_TRUE(flba1.Equals(&flba2));
-  ASSERT_FALSE(flba1.Equals(&flba3));
-  ASSERT_FALSE(flba1.Equals(&flba4));
-  ASSERT_FALSE(flba1.Equals(&flba5));
-}
-
-TEST_F(TestPrimitiveNode, PhysicalLogicalMapping) {
-  ASSERT_NO_THROW(
-      PrimitiveNode::Make("foo", Repetition::REQUIRED, Type::INT32, LogicalType::INT_32));
-  ASSERT_NO_THROW(PrimitiveNode::Make("foo", Repetition::REQUIRED, Type::BYTE_ARRAY,
-                                      LogicalType::JSON));
-  ASSERT_THROW(
-      PrimitiveNode::Make("foo", Repetition::REQUIRED, Type::INT32, LogicalType::JSON),
-      ParquetException);
-  ASSERT_NO_THROW(PrimitiveNode::Make("foo", Repetition::REQUIRED, Type::INT64,
-                                      LogicalType::TIMESTAMP_MILLIS));
-  ASSERT_THROW(
-      PrimitiveNode::Make("foo", Repetition::REQUIRED, Type::INT32, LogicalType::INT_64),
-      ParquetException);
-  ASSERT_THROW(PrimitiveNode::Make("foo", Repetition::REQUIRED, Type::BYTE_ARRAY,
-                                   LogicalType::INT_8),
-               ParquetException);
-  ASSERT_THROW(PrimitiveNode::Make("foo", Repetition::REQUIRED, Type::BYTE_ARRAY,
-                                   LogicalType::INTERVAL),
-               ParquetException);
-  ASSERT_THROW(PrimitiveNode::Make("foo", Repetition::REQUIRED,
-                                   Type::FIXED_LEN_BYTE_ARRAY, LogicalType::ENUM),
-               ParquetException);
-  ASSERT_NO_THROW(PrimitiveNode::Make("foo", Repetition::REQUIRED, Type::BYTE_ARRAY,
-                                      LogicalType::ENUM));
-  ASSERT_THROW(
-      PrimitiveNode::Make("foo", Repetition::REQUIRED, Type::FIXED_LEN_BYTE_ARRAY,
-                          LogicalType::DECIMAL, 0, 2, 4),
-      ParquetException);
-  ASSERT_THROW(PrimitiveNode::Make("foo", Repetition::REQUIRED, Type::FLOAT,
-                                   LogicalType::DECIMAL, 0, 2, 4),
-               ParquetException);
-  ASSERT_THROW(
-      PrimitiveNode::Make("foo", Repetition::REQUIRED, Type::FIXED_LEN_BYTE_ARRAY,
-                          LogicalType::DECIMAL, 0, 4, 0),
-      ParquetException);
-  ASSERT_THROW(
-      PrimitiveNode::Make("foo", Repetition::REQUIRED, Type::FIXED_LEN_BYTE_ARRAY,
-                          LogicalType::DECIMAL, 10, 0, 4),
-      ParquetException);
-  ASSERT_THROW(
-      PrimitiveNode::Make("foo", Repetition::REQUIRED, Type::FIXED_LEN_BYTE_ARRAY,
-                          LogicalType::DECIMAL, 10, 4, -1),
-      ParquetException);
-  ASSERT_THROW(
-      PrimitiveNode::Make("foo", Repetition::REQUIRED, Type::FIXED_LEN_BYTE_ARRAY,
-                          LogicalType::DECIMAL, 10, 2, 4),
-      ParquetException);
-  ASSERT_NO_THROW(PrimitiveNode::Make("foo", Repetition::REQUIRED,
-                                      Type::FIXED_LEN_BYTE_ARRAY, LogicalType::DECIMAL,
-                                      10, 6, 4));
-  ASSERT_NO_THROW(PrimitiveNode::Make("foo", Repetition::REQUIRED,
-                                      Type::FIXED_LEN_BYTE_ARRAY, LogicalType::INTERVAL,
-                                      12));
-  ASSERT_THROW(PrimitiveNode::Make("foo", Repetition::REQUIRED,
-                                   Type::FIXED_LEN_BYTE_ARRAY, LogicalType::INTERVAL, 10),
-               ParquetException);
-}
-
-// ----------------------------------------------------------------------
-// Group node
-
-class TestGroupNode : public ::testing::Test {
- public:
-  NodeVector Fields1() {
-    NodeVector fields;
-
-    fields.push_back(Int32("one", Repetition::REQUIRED));
-    fields.push_back(Int64("two"));
-    fields.push_back(Double("three"));
-
-    return fields;
-  }
-
-  NodeVector Fields2() {
-    // Fields with a duplicate name
-    NodeVector fields;
-
-    fields.push_back(Int32("duplicate", Repetition::REQUIRED));
-    fields.push_back(Int64("unique"));
-    fields.push_back(Double("duplicate"));
-
-    return fields;
-  }
-};
-
-TEST_F(TestGroupNode, Attrs) {
-  NodeVector fields = Fields1();
-
-  GroupNode node1("foo", Repetition::REPEATED, fields);
-  GroupNode node2("bar", Repetition::OPTIONAL, fields, LogicalType::LIST);
-
-  ASSERT_EQ("foo", node1.name());
-
-  ASSERT_TRUE(node1.is_group());
-  ASSERT_FALSE(node1.is_primitive());
-
-  ASSERT_EQ(fields.size(), node1.field_count());
-
-  ASSERT_TRUE(node1.is_repeated());
-  ASSERT_TRUE(node2.is_optional());
-
-  ASSERT_EQ(Repetition::REPEATED, node1.repetition());
-  ASSERT_EQ(Repetition::OPTIONAL, node2.repetition());
-
-  ASSERT_EQ(Node::GROUP, node1.node_type());
-
-  // logical types
-  ASSERT_EQ(LogicalType::NONE, node1.logical_type());
-  ASSERT_EQ(LogicalType::LIST, node2.logical_type());
-}
-
-TEST_F(TestGroupNode, Equals) {
-  NodeVector f1 = Fields1();
-  NodeVector f2 = Fields1();
-
-  GroupNode group1("group", Repetition::REPEATED, f1);
-  GroupNode group2("group", Repetition::REPEATED, f2);
-  GroupNode group3("group2", Repetition::REPEATED, f2);
-
-  // This is copied in the GroupNode ctor, so this is okay
-  f2.push_back(Float("four", Repetition::OPTIONAL));
-  GroupNode group4("group", Repetition::REPEATED, f2);
-  GroupNode group5("group", Repetition::REPEATED, Fields1());
-
-  ASSERT_TRUE(group1.Equals(&group1));
-  ASSERT_TRUE(group1.Equals(&group2));
-  ASSERT_FALSE(group1.Equals(&group3));
-
-  ASSERT_FALSE(group1.Equals(&group4));
-  ASSERT_FALSE(group5.Equals(&group4));
-}
-
-TEST_F(TestGroupNode, FieldIndex) {
-  NodeVector fields = Fields1();
-  GroupNode group("group", Repetition::REQUIRED, fields);
-  for (size_t i = 0; i < fields.size(); i++) {
-    auto field = group.field(static_cast<int>(i));
-    ASSERT_EQ(i, group.FieldIndex(*field));
-  }
-
-  // Test a non field node
-  auto non_field_alien = Int32("alien", Repetition::REQUIRED);   // other name
-  auto non_field_familiar = Int32("one", Repetition::REPEATED);  // other node
-  ASSERT_TRUE(group.FieldIndex(*non_field_alien) < 0);
-  ASSERT_TRUE(group.FieldIndex(*non_field_familiar) < 0);
-}
-
-TEST_F(TestGroupNode, FieldIndexDuplicateName) {
-  NodeVector fields = Fields2();
-  GroupNode group("group", Repetition::REQUIRED, fields);
-  for (size_t i = 0; i < fields.size(); i++) {
-    auto field = group.field(static_cast<int>(i));
-    ASSERT_EQ(i, group.FieldIndex(*field));
-  }
-}
-
-// ----------------------------------------------------------------------
-// Test convert group
-
-class TestSchemaConverter : public ::testing::Test {
- public:
-  void setUp() { name_ = "parquet_schema"; }
-
-  void Convert(const parquet::format::SchemaElement* elements, int length) {
-    FlatSchemaConverter converter(elements, length);
-    node_ = converter.Convert();
-    ASSERT_TRUE(node_->is_group());
-    group_ = static_cast<const GroupNode*>(node_.get());
-  }
-
- protected:
-  std::string name_;
-  const GroupNode* group_;
-  std::unique_ptr<Node> node_;
-};
-
-bool check_for_parent_consistency(const GroupNode* node) {
-  // Each node should have the group as parent
-  for (int i = 0; i < node->field_count(); i++) {
-    const NodePtr& field = node->field(i);
-    if (field->parent() != node) {
-      return false;
-    }
-    if (field->is_group()) {
-      const GroupNode* group = static_cast<GroupNode*>(field.get());
-      if (!check_for_parent_consistency(group)) {
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-TEST_F(TestSchemaConverter, NestedExample) {
-  SchemaElement elt;
-  std::vector<SchemaElement> elements;
-  elements.push_back(NewGroup(name_, FieldRepetitionType::REPEATED, 2, 0));
-
-  // A primitive one
-  elements.push_back(
-      NewPrimitive("a", FieldRepetitionType::REQUIRED, format::Type::INT32, 1));
-
-  // A group
-  elements.push_back(NewGroup("bag", FieldRepetitionType::OPTIONAL, 1, 2));
-
-  // 3-level list encoding, by hand
-  elt = NewGroup("b", FieldRepetitionType::REPEATED, 1, 3);
-  elt.__set_converted_type(ConvertedType::LIST);
-  elements.push_back(elt);
-  elements.push_back(
-      NewPrimitive("item", FieldRepetitionType::OPTIONAL, format::Type::INT64, 4));
-
-  ASSERT_NO_FATAL_FAILURE(Convert(&elements[0], static_cast<int>(elements.size())));
-
-  // Construct the expected schema
-  NodeVector fields;
-  fields.push_back(Int32("a", Repetition::REQUIRED));
-
-  // 3-level list encoding
-  NodePtr item = Int64("item");
-  NodePtr list(GroupNode::Make("b", Repetition::REPEATED, {item}, LogicalType::LIST));
-  NodePtr bag(GroupNode::Make("bag", Repetition::OPTIONAL, {list}));
-  fields.push_back(bag);
-
-  NodePtr schema = GroupNode::Make(name_, Repetition::REPEATED, fields);
-
-  ASSERT_TRUE(schema->Equals(group_));
-
-  // Check that the parent relationship in each node is consitent
-  ASSERT_EQ(group_->parent(), nullptr);
-  ASSERT_TRUE(check_for_parent_consistency(group_));
-}
-
-TEST_F(TestSchemaConverter, InvalidRoot) {
-  // According to the Parquet specification, the first element in the
-  // list<SchemaElement> is a group whose children (and their descendants)
-  // contain all of the rest of the flattened schema elements. If the first
-  // element is not a group, it is a malformed Parquet file.
-
-  SchemaElement elements[2];
-  elements[0] =
-      NewPrimitive("not-a-group", FieldRepetitionType::REQUIRED, format::Type::INT32, 0);
-  ASSERT_THROW(Convert(elements, 2), ParquetException);
-
-  // While the Parquet spec indicates that the root group should have REPEATED
-  // repetition type, some implementations may return REQUIRED or OPTIONAL
-  // groups as the first element. These tests check that this is okay as a
-  // practicality matter.
-  elements[0] = NewGroup("not-repeated", FieldRepetitionType::REQUIRED, 1, 0);
-  elements[1] = NewPrimitive("a", FieldRepetitionType::REQUIRED, format::Type::INT32, 1);
-  ASSERT_NO_FATAL_FAILURE(Convert(elements, 2));
-
-  elements[0] = NewGroup("not-repeated", FieldRepetitionType::OPTIONAL, 1, 0);
-  ASSERT_NO_FATAL_FAILURE(Convert(elements, 2));
-}
-
-TEST_F(TestSchemaConverter, NotEnoughChildren) {
-  // Throw a ParquetException, but don't core dump or anything
-  SchemaElement elt;
-  std::vector<SchemaElement> elements;
-  elements.push_back(NewGroup(name_, FieldRepetitionType::REPEATED, 2, 0));
-  ASSERT_THROW(Convert(&elements[0], 1), ParquetException);
-}
-
-// ----------------------------------------------------------------------
-// Schema tree flatten / unflatten
-
-class TestSchemaFlatten : public ::testing::Test {
- public:
-  void setUp() { name_ = "parquet_schema"; }
-
-  void Flatten(const GroupNode* schema) { ToParquet(schema, &elements_); }
-
- protected:
-  std::string name_;
-  std::vector<format::SchemaElement> elements_;
-};
-
-TEST_F(TestSchemaFlatten, DecimalMetadata) {
-  // Checks that DecimalMetadata is only set for DecimalTypes
-  NodePtr node = PrimitiveNode::Make("decimal", Repetition::REQUIRED, Type::INT64,
-                                     LogicalType::DECIMAL, -1, 8, 4);
-  NodePtr group =
-      GroupNode::Make("group", Repetition::REPEATED, {node}, LogicalType::LIST);
-  Flatten(reinterpret_cast<GroupNode*>(group.get()));
-  ASSERT_EQ("decimal", elements_[1].name);
-  ASSERT_TRUE(elements_[1].__isset.precision);
-  ASSERT_TRUE(elements_[1].__isset.scale);
-
-  elements_.clear();
-  // Not for integers with no logical type
-  group =
-      GroupNode::Make("group", Repetition::REPEATED, {Int64("int64")}, LogicalType::LIST);
-  Flatten(reinterpret_cast<GroupNode*>(group.get()));
-  ASSERT_EQ("int64", elements_[1].name);
-  ASSERT_FALSE(elements_[0].__isset.precision);
-  ASSERT_FALSE(elements_[0].__isset.scale);
-}
-
-TEST_F(TestSchemaFlatten, NestedExample) {
-  SchemaElement elt;
-  std::vector<SchemaElement> elements;
-  elements.push_back(NewGroup(name_, FieldRepetitionType::REPEATED, 2, 0));
-
-  // A primitive one
-  elements.push_back(
-      NewPrimitive("a", FieldRepetitionType::REQUIRED, format::Type::INT32, 1));
-
-  // A group
-  elements.push_back(NewGroup("bag", FieldRepetitionType::OPTIONAL, 1, 2));
-
-  // 3-level list encoding, by hand
-  elt = NewGroup("b", FieldRepetitionType::REPEATED, 1, 3);
-  elt.__set_converted_type(ConvertedType::LIST);
-  elements.push_back(elt);
-  elements.push_back(
-      NewPrimitive("item", FieldRepetitionType::OPTIONAL, format::Type::INT64, 4));
-
-  // Construct the schema
-  NodeVector fields;
-  fields.push_back(Int32("a", Repetition::REQUIRED));
-
-  // 3-level list encoding
-  NodePtr item = Int64("item");
-  NodePtr list(GroupNode::Make("b", Repetition::REPEATED, {item}, LogicalType::LIST));
-  NodePtr bag(GroupNode::Make("bag", Repetition::OPTIONAL, {list}));
-  fields.push_back(bag);
-
-  NodePtr schema = GroupNode::Make(name_, Repetition::REPEATED, fields);
-
-  Flatten(static_cast<GroupNode*>(schema.get()));
-  ASSERT_EQ(elements_.size(), elements.size());
-  for (size_t i = 0; i < elements_.size(); i++) {
-    ASSERT_EQ(elements_[i], elements[i]);
-  }
-}
-
-TEST(TestColumnDescriptor, TestAttrs) {
-  NodePtr node = PrimitiveNode::Make("name", Repetition::OPTIONAL, Type::BYTE_ARRAY,
-                                     LogicalType::UTF8);
-  ColumnDescriptor descr(node, 4, 1);
-
-  ASSERT_EQ("name", descr.name());
-  ASSERT_EQ(4, descr.max_definition_level());
-  ASSERT_EQ(1, descr.max_repetition_level());
-
-  ASSERT_EQ(Type::BYTE_ARRAY, descr.physical_type());
-
-  ASSERT_EQ(-1, descr.type_length());
-
-  // Test FIXED_LEN_BYTE_ARRAY
-  node = PrimitiveNode::Make("name", Repetition::OPTIONAL, Type::FIXED_LEN_BYTE_ARRAY,
-                             LogicalType::DECIMAL, 12, 10, 4);
-  descr = ColumnDescriptor(node, 4, 1);
-
-  ASSERT_EQ(Type::FIXED_LEN_BYTE_ARRAY, descr.physical_type());
-  ASSERT_EQ(12, descr.type_length());
-}
-
-class TestSchemaDescriptor : public ::testing::Test {
- public:
-  void setUp() {}
-
- protected:
-  SchemaDescriptor descr_;
-};
-
-TEST_F(TestSchemaDescriptor, InitNonGroup) {
-  NodePtr node = PrimitiveNode::Make("field", Repetition::OPTIONAL, Type::INT32);
-
-  ASSERT_THROW(descr_.Init(node), ParquetException);
-}
-
-TEST_F(TestSchemaDescriptor, Equals) {
-  NodePtr schema;
-
-  NodePtr inta = Int32("a", Repetition::REQUIRED);
-  NodePtr intb = Int64("b", Repetition::OPTIONAL);
-  NodePtr intb2 = Int64("b2", Repetition::OPTIONAL);
-  NodePtr intc = ByteArray("c", Repetition::REPEATED);
-
-  NodePtr item1 = Int64("item1", Repetition::REQUIRED);
-  NodePtr item2 = Boolean("item2", Repetition::OPTIONAL);
-  NodePtr item3 = Int32("item3", Repetition::REPEATED);
-  NodePtr list(GroupNode::Make("records", Repetition::REPEATED, {item1, item2, item3},
-                               LogicalType::LIST));
-
-  NodePtr bag(GroupNode::Make("bag", Repetition::OPTIONAL, {list}));
-  NodePtr bag2(GroupNode::Make("bag", Repetition::REQUIRED, {list}));
-
-  SchemaDescriptor descr1;
-  descr1.Init(GroupNode::Make("schema", Repetition::REPEATED, {inta, intb, intc, bag}));
-
-  ASSERT_TRUE(descr1.Equals(descr1));
-
-  SchemaDescriptor descr2;
-  descr2.Init(GroupNode::Make("schema", Repetition::REPEATED, {inta, intb, intc, bag2}));
-  ASSERT_FALSE(descr1.Equals(descr2));
-
-  SchemaDescriptor descr3;
-  descr3.Init(GroupNode::Make("schema", Repetition::REPEATED, {inta, intb2, intc, bag}));
-  ASSERT_FALSE(descr1.Equals(descr3));
-
-  // Robust to name of parent node
-  SchemaDescriptor descr4;
-  descr4.Init(GroupNode::Make("SCHEMA", Repetition::REPEATED, {inta, intb, intc, bag}));
-  ASSERT_TRUE(descr1.Equals(descr4));
-
-  SchemaDescriptor descr5;
-  descr5.Init(
-      GroupNode::Make("schema", Repetition::REPEATED, {inta, intb, intc, bag, intb2}));
-  ASSERT_FALSE(descr1.Equals(descr5));
-
-  // Different max repetition / definition levels
-  ColumnDescriptor col1(inta, 5, 1);
-  ColumnDescriptor col2(inta, 6, 1);
-  ColumnDescriptor col3(inta, 5, 2);
-
-  ASSERT_TRUE(col1.Equals(col1));
-  ASSERT_FALSE(col1.Equals(col2));
-  ASSERT_FALSE(col1.Equals(col3));
-}
-
-TEST_F(TestSchemaDescriptor, BuildTree) {
-  NodeVector fields;
-  NodePtr schema;
-
-  NodePtr inta = Int32("a", Repetition::REQUIRED);
-  fields.push_back(inta);
-  fields.push_back(Int64("b", Repetition::OPTIONAL));
-  fields.push_back(ByteArray("c", Repetition::REPEATED));
-
-  // 3-level list encoding
-  NodePtr item1 = Int64("item1", Repetition::REQUIRED);
-  NodePtr item2 = Boolean("item2", Repetition::OPTIONAL);
-  NodePtr item3 = Int32("item3", Repetition::REPEATED);
-  NodePtr list(GroupNode::Make("records", Repetition::REPEATED, {item1, item2, item3},
-                               LogicalType::LIST));
-  NodePtr bag(GroupNode::Make("bag", Repetition::OPTIONAL, {list}));
-  fields.push_back(bag);
-
-  schema = GroupNode::Make("schema", Repetition::REPEATED, fields);
-
-  descr_.Init(schema);
-
-  int nleaves = 6;
-
-  // 6 leaves
-  ASSERT_EQ(nleaves, descr_.num_columns());
-
-  //                             mdef mrep
-  // required int32 a            0    0
-  // optional int64 b            1    0
-  // repeated byte_array c       1    1
-  // optional group bag          1    0
-  //   repeated group records    2    1
-  //     required int64 item1    2    1
-  //     optional boolean item2  3    1
-  //     repeated int32 item3    3    2
-  int16_t ex_max_def_levels[6] = {0, 1, 1, 2, 3, 3};
-  int16_t ex_max_rep_levels[6] = {0, 0, 1, 1, 1, 2};
-
-  for (int i = 0; i < nleaves; ++i) {
-    const ColumnDescriptor* col = descr_.Column(i);
-    EXPECT_EQ(ex_max_def_levels[i], col->max_definition_level()) << i;
-    EXPECT_EQ(ex_max_rep_levels[i], col->max_repetition_level()) << i;
-  }
-
-  ASSERT_EQ(descr_.Column(0)->path()->ToDotString(), "a");
-  ASSERT_EQ(descr_.Column(1)->path()->ToDotString(), "b");
-  ASSERT_EQ(descr_.Column(2)->path()->ToDotString(), "c");
-  ASSERT_EQ(descr_.Column(3)->path()->ToDotString(), "bag.records.item1");
-  ASSERT_EQ(descr_.Column(4)->path()->ToDotString(), "bag.records.item2");
-  ASSERT_EQ(descr_.Column(5)->path()->ToDotString(), "bag.records.item3");
-
-  for (int i = 0; i < nleaves; ++i) {
-    auto col = descr_.Column(i);
-    ASSERT_EQ(i, descr_.ColumnIndex(*col->schema_node()));
-  }
-
-  // Test non-column nodes find
-  NodePtr non_column_alien = Int32("alien", Repetition::REQUIRED);  // other path
-  NodePtr non_column_familiar = Int32("a", Repetition::REPEATED);   // other node
-  ASSERT_TRUE(descr_.ColumnIndex(*non_column_alien) < 0);
-  ASSERT_TRUE(descr_.ColumnIndex(*non_column_familiar) < 0);
-
-  ASSERT_EQ(inta.get(), descr_.GetColumnRoot(0));
-  ASSERT_EQ(bag.get(), descr_.GetColumnRoot(3));
-  ASSERT_EQ(bag.get(), descr_.GetColumnRoot(4));
-  ASSERT_EQ(bag.get(), descr_.GetColumnRoot(5));
-
-  ASSERT_EQ(schema.get(), descr_.group_node());
-
-  // Init clears the leaves
-  descr_.Init(schema);
-  ASSERT_EQ(nleaves, descr_.num_columns());
-}
-
-static std::string Print(const NodePtr& node) {
-  std::stringstream ss;
-  PrintSchema(node.get(), ss);
-  return ss.str();
-}
-
-TEST(TestSchemaPrinter, Examples) {
-  // Test schema 1
-  NodeVector fields;
-  fields.push_back(Int32("a", Repetition::REQUIRED));
-
-  // 3-level list encoding
-  NodePtr item1 = Int64("item1");
-  NodePtr item2 = Boolean("item2", Repetition::REQUIRED);
-  NodePtr list(
-      GroupNode::Make("b", Repetition::REPEATED, {item1, item2}, LogicalType::LIST));
-  NodePtr bag(GroupNode::Make("bag", Repetition::OPTIONAL, {list}));
-  fields.push_back(bag);
-
-  fields.push_back(PrimitiveNode::Make("c", Repetition::REQUIRED, Type::INT32,
-                                       LogicalType::DECIMAL, -1, 3, 2));
-
-  NodePtr schema = GroupNode::Make("schema", Repetition::REPEATED, fields);
-
-  std::string result = Print(schema);
-  std::string expected = R"(message schema {
-  required int32 a;
-  optional group bag {
-    repeated group b (LIST) {
-      optional int64 item1;
-      required boolean item2;
-    }
-  }
-  required int32 c (DECIMAL(3,2));
-}
-)";
-  ASSERT_EQ(expected, result);
-}
-
-}  // namespace schema
-}  // namespace parquet
diff --git a/src/parquet/schema.cc b/src/parquet/schema.cc
deleted file mode 100644
index 7718781..0000000
--- a/src/parquet/schema.cc
+++ /dev/null
@@ -1,756 +0,0 @@
-// 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.
-
-#include "parquet/schema.h"
-#include "parquet/schema-internal.h"
-
-#include <algorithm>
-#include <memory>
-#include <sstream>
-#include <string>
-
-#include "parquet/exception.h"
-#include "parquet/parquet_types.h"
-#include "parquet/thrift.h"
-
-using parquet::format::SchemaElement;
-
-namespace parquet {
-
-namespace schema {
-
-// ----------------------------------------------------------------------
-// ColumnPath
-
-std::shared_ptr<ColumnPath> ColumnPath::FromDotString(const std::string& dotstring) {
-  std::stringstream ss(dotstring);
-  std::string item;
-  std::vector<std::string> path;
-  while (std::getline(ss, item, '.')) {
-    path.push_back(item);
-  }
-  return std::shared_ptr<ColumnPath>(new ColumnPath(std::move(path)));
-}
-
-std::shared_ptr<ColumnPath> ColumnPath::FromNode(const Node& node) {
-  // Build the path in reverse order as we traverse the nodes to the top
-  std::vector<std::string> rpath_;
-  const Node* cursor = &node;
-  // The schema node is not part of the ColumnPath
-  while (cursor->parent()) {
-    rpath_.push_back(cursor->name());
-    cursor = cursor->parent();
-  }
-
-  // Build ColumnPath in correct order
-  std::vector<std::string> path(rpath_.crbegin(), rpath_.crend());
-  return std::make_shared<ColumnPath>(std::move(path));
-}
-
-std::shared_ptr<ColumnPath> ColumnPath::extend(const std::string& node_name) const {
-  std::vector<std::string> path;
-  path.reserve(path_.size() + 1);
-  path.resize(path_.size() + 1);
-  std::copy(path_.cbegin(), path_.cend(), path.begin());
-  path[path_.size()] = node_name;
-
-  return std::shared_ptr<ColumnPath>(new ColumnPath(std::move(path)));
-}
-
-std::string ColumnPath::ToDotString() const {
-  std::stringstream ss;
-  for (auto it = path_.cbegin(); it != path_.cend(); ++it) {
-    if (it != path_.cbegin()) {
-      ss << ".";
-    }
-    ss << *it;
-  }
-  return ss.str();
-}
-
-const std::vector<std::string>& ColumnPath::ToDotVector() const { return path_; }
-
-// ----------------------------------------------------------------------
-// Base node
-
-const std::shared_ptr<ColumnPath> Node::path() const {
-  // TODO(itaiin): Cache the result, or more precisely, cache ->ToDotString()
-  //    since it is being used to access the leaf nodes
-  return ColumnPath::FromNode(*this);
-}
-
-bool Node::EqualsInternal(const Node* other) const {
-  return type_ == other->type_ && name_ == other->name_ &&
-         repetition_ == other->repetition_ && logical_type_ == other->logical_type_;
-}
-
-void Node::SetParent(const Node* parent) { parent_ = parent; }
-
-// ----------------------------------------------------------------------
-// Primitive node
-
-PrimitiveNode::PrimitiveNode(const std::string& name, Repetition::type repetition,
-                             Type::type type, LogicalType::type logical_type, int length,
-                             int precision, int scale, int id)
-    : Node(Node::PRIMITIVE, name, repetition, logical_type, id),
-      physical_type_(type),
-      type_length_(length) {
-  std::stringstream ss;
-
-  // PARQUET-842: In an earlier revision, decimal_metadata_.isset was being
-  // set to true, but Impala will raise an incompatible metadata in such cases
-  memset(&decimal_metadata_, 0, sizeof(decimal_metadata_));
-
-  // Check if the physical and logical types match
-  // Mapping referred from Apache parquet-mr as on 2016-02-22
-  switch (logical_type) {
-    case LogicalType::NONE:
-      // Logical type not set
-      break;
-    case LogicalType::UTF8:
-    case LogicalType::JSON:
-    case LogicalType::BSON:
-      if (type != Type::BYTE_ARRAY) {
-        ss << LogicalTypeToString(logical_type);
-        ss << " can only annotate BYTE_ARRAY fields";
-        throw ParquetException(ss.str());
-      }
-      break;
-    case LogicalType::DECIMAL:
-      if ((type != Type::INT32) && (type != Type::INT64) && (type != Type::BYTE_ARRAY) &&
-          (type != Type::FIXED_LEN_BYTE_ARRAY)) {
-        ss << "DECIMAL can only annotate INT32, INT64, BYTE_ARRAY, and FIXED";
-        throw ParquetException(ss.str());
-      }
-      if (precision <= 0) {
-        ss << "Invalid DECIMAL precision: " << precision
-           << ". Precision must be a number between 1 and 38 inclusive";
-        throw ParquetException(ss.str());
-      }
-      if (scale < 0) {
-        ss << "Invalid DECIMAL scale: " << scale
-           << ". Scale must be a number between 0 and precision inclusive";
-        throw ParquetException(ss.str());
-      }
-      if (scale > precision) {
-        ss << "Invalid DECIMAL scale " << scale;
-        ss << " cannot be greater than precision " << precision;
-        throw ParquetException(ss.str());
-      }
-      decimal_metadata_.isset = true;
-      decimal_metadata_.precision = precision;
-      decimal_metadata_.scale = scale;
-      break;
-    case LogicalType::DATE:
-    case LogicalType::TIME_MILLIS:
-    case LogicalType::UINT_8:
-    case LogicalType::UINT_16:
-    case LogicalType::UINT_32:
-    case LogicalType::INT_8:
-    case LogicalType::INT_16:
-    case LogicalType::INT_32:
-      if (type != Type::INT32) {
-        ss << LogicalTypeToString(logical_type);
-        ss << " can only annotate INT32";
-        throw ParquetException(ss.str());
-      }
-      break;
-    case LogicalType::TIME_MICROS:
-    case LogicalType::TIMESTAMP_MILLIS:
-    case LogicalType::TIMESTAMP_MICROS:
-    case LogicalType::UINT_64:
-    case LogicalType::INT_64:
-      if (type != Type::INT64) {
-        ss << LogicalTypeToString(logical_type);
-        ss << " can only annotate INT64";
-        throw ParquetException(ss.str());
-      }
-      break;
-    case LogicalType::INTERVAL:
-      if ((type != Type::FIXED_LEN_BYTE_ARRAY) || (length != 12)) {
-        ss << "INTERVAL can only annotate FIXED_LEN_BYTE_ARRAY(12)";
-        throw ParquetException(ss.str());
-      }
-      break;
-    case LogicalType::ENUM:
-      if (type != Type::BYTE_ARRAY) {
-        ss << "ENUM can only annotate BYTE_ARRAY fields";
-        throw ParquetException(ss.str());
-      }
-      break;
-    case LogicalType::NA:
-      // NA can annotate any type
-      break;
-    default:
-      ss << LogicalTypeToString(logical_type);
-      ss << " can not be applied to a primitive type";
-      throw ParquetException(ss.str());
-  }
-  if (type == Type::FIXED_LEN_BYTE_ARRAY) {
-    if (length <= 0) {
-      ss << "Invalid FIXED_LEN_BYTE_ARRAY length: " << length;
-      throw ParquetException(ss.str());
-    }
-    type_length_ = length;
-  }
-}
-
-bool PrimitiveNode::EqualsInternal(const PrimitiveNode* other) const {
-  bool is_equal = true;
-  if ((physical_type_ != other->physical_type_) ||
-      (logical_type_ != other->logical_type_)) {
-    return false;
-  }
-  if (logical_type_ == LogicalType::DECIMAL) {
-    is_equal &= (decimal_metadata_.precision == other->decimal_metadata_.precision) &&
-                (decimal_metadata_.scale == other->decimal_metadata_.scale);
-  }
-  if (physical_type_ == Type::FIXED_LEN_BYTE_ARRAY) {
-    is_equal &= (type_length_ == other->type_length_);
-  }
-  return is_equal;
-}
-
-bool PrimitiveNode::Equals(const Node* other) const {
-  if (!Node::EqualsInternal(other)) {
-    return false;
-  }
-  return EqualsInternal(static_cast<const PrimitiveNode*>(other));
-}
-
-void PrimitiveNode::Visit(Node::Visitor* visitor) { visitor->Visit(this); }
-
-void PrimitiveNode::VisitConst(Node::ConstVisitor* visitor) const {
-  visitor->Visit(this);
-}
-
-// ----------------------------------------------------------------------
-// Group node
-
-bool GroupNode::EqualsInternal(const GroupNode* other) const {
-  if (this == other) {
-    return true;
-  }
-  if (this->field_count() != other->field_count()) {
-    return false;
-  }
-  for (int i = 0; i < this->field_count(); ++i) {
-    if (!this->field(i)->Equals(other->field(i).get())) {
-      return false;
-    }
-  }
-  return true;
-}
-
-bool GroupNode::Equals(const Node* other) const {
-  if (!Node::EqualsInternal(other)) {
-    return false;
-  }
-  return EqualsInternal(static_cast<const GroupNode*>(other));
-}
-
-int GroupNode::FieldIndex(const std::string& name) const {
-  auto search = field_name_to_idx_.find(name);
-  if (search == field_name_to_idx_.end()) {
-    // Not found
-    return -1;
-  }
-  return search->second;
-}
-
-int GroupNode::FieldIndex(const Node& node) const {
-  auto search = field_name_to_idx_.equal_range(node.name());
-  for (auto it = search.first; it != search.second; ++it) {
-    const int idx = it->second;
-    if (&node == field(idx).get()) {
-      return idx;
-    }
-  }
-  return -1;
-}
-
-void GroupNode::Visit(Node::Visitor* visitor) { visitor->Visit(this); }
-
-void GroupNode::VisitConst(Node::ConstVisitor* visitor) const { visitor->Visit(this); }
-
-// ----------------------------------------------------------------------
-// Node construction from Parquet metadata
-
-struct NodeParams {
-  explicit NodeParams(const std::string& name) : name(name) {}
-
-  const std::string& name;
-  Repetition::type repetition;
-  LogicalType::type logical_type;
-};
-
-static inline NodeParams GetNodeParams(const format::SchemaElement* element) {
-  NodeParams params(element->name);
-
-  params.repetition = FromThrift(element->repetition_type);
-  if (element->__isset.converted_type) {
-    params.logical_type = FromThrift(element->converted_type);
-  } else {
-    params.logical_type = LogicalType::NONE;
-  }
-  return params;
-}
-
-std::unique_ptr<Node> GroupNode::FromParquet(const void* opaque_element, int node_id,
-                                             const NodeVector& fields) {
-  const format::SchemaElement* element =
-      static_cast<const format::SchemaElement*>(opaque_element);
-  NodeParams params = GetNodeParams(element);
-  return std::unique_ptr<Node>(new GroupNode(params.name, params.repetition, fields,
-                                             params.logical_type, node_id));
-}
-
-std::unique_ptr<Node> PrimitiveNode::FromParquet(const void* opaque_element,
-                                                 int node_id) {
-  const format::SchemaElement* element =
-      static_cast<const format::SchemaElement*>(opaque_element);
-  NodeParams params = GetNodeParams(element);
-
-  std::unique_ptr<PrimitiveNode> result =
-      std::unique_ptr<PrimitiveNode>(new PrimitiveNode(
-          params.name, params.repetition, FromThrift(element->type), params.logical_type,
-          element->type_length, element->precision, element->scale, node_id));
-
-  // Return as unique_ptr to the base type
-  return std::unique_ptr<Node>(result.release());
-}
-
-void GroupNode::ToParquet(void* opaque_element) const {
-  format::SchemaElement* element = static_cast<format::SchemaElement*>(opaque_element);
-  element->__set_name(name_);
-  element->__set_num_children(field_count());
-  element->__set_repetition_type(ToThrift(repetition_));
-  if (logical_type_ != LogicalType::NONE) {
-    element->__set_converted_type(ToThrift(logical_type_));
-  }
-}
-
-void PrimitiveNode::ToParquet(void* opaque_element) const {
-  format::SchemaElement* element = static_cast<format::SchemaElement*>(opaque_element);
-
-  element->__set_name(name_);
-  element->__set_repetition_type(ToThrift(repetition_));
-  if (logical_type_ != LogicalType::NONE) {
-    element->__set_converted_type(ToThrift(logical_type_));
-  }
-  element->__set_type(ToThrift(physical_type_));
-  if (physical_type_ == Type::FIXED_LEN_BYTE_ARRAY) {
-    element->__set_type_length(type_length_);
-  }
-  if (decimal_metadata_.isset) {
-    element->__set_precision(decimal_metadata_.precision);
-    element->__set_scale(decimal_metadata_.scale);
-  }
-}
-
-// ----------------------------------------------------------------------
-// Schema converters
-
-std::unique_ptr<Node> FlatSchemaConverter::Convert() {
-  const SchemaElement& root = elements_[0];
-
-  // Validate the root node
-  if (root.num_children == 0) {
-    throw ParquetException("Root node did not have children");
-  }
-
-  // Relaxing this restriction as some implementations don't set this
-  // if (root.repetition_type != FieldRepetitionType::REPEATED) {
-  //   throw ParquetException("Root node was not FieldRepetitionType::REPEATED");
-  // }
-
-  return NextNode();
-}
-
-std::unique_ptr<Node> FlatSchemaConverter::NextNode() {
-  const SchemaElement& element = Next();
-
-  int node_id = next_id();
-
-  const void* opaque_element = static_cast<const void*>(&element);
-
-  if (element.num_children == 0) {
-    // Leaf (primitive) node
-    return PrimitiveNode::FromParquet(opaque_element, node_id);
-  } else {
-    // Group
-    NodeVector fields;
-    for (int i = 0; i < element.num_children; ++i) {
-      std::unique_ptr<Node> field = NextNode();
-      fields.push_back(NodePtr(field.release()));
-    }
-    return GroupNode::FromParquet(opaque_element, node_id, fields);
-  }
-}
-
-const format::SchemaElement& FlatSchemaConverter::Next() {
-  if (pos_ == length_) {
-    throw ParquetException("Malformed schema: not enough SchemaElement values");
-  }
-  return elements_[pos_++];
-}
-
-std::shared_ptr<SchemaDescriptor> FromParquet(const std::vector<SchemaElement>& schema) {
-  FlatSchemaConverter converter(&schema[0], static_cast<int>(schema.size()));
-  std::unique_ptr<Node> root = converter.Convert();
-
-  std::shared_ptr<SchemaDescriptor> descr = std::make_shared<SchemaDescriptor>();
-  descr->Init(std::shared_ptr<GroupNode>(static_cast<GroupNode*>(root.release())));
-
-  return descr;
-}
-
-void ToParquet(const GroupNode* schema, std::vector<format::SchemaElement>* out) {
-  SchemaFlattener flattener(schema, out);
-  flattener.Flatten();
-}
-
-class SchemaVisitor : public Node::ConstVisitor {
- public:
-  explicit SchemaVisitor(std::vector<format::SchemaElement>* elements)
-      : elements_(elements) {}
-
-  void Visit(const Node* node) override {
-    format::SchemaElement element;
-    node->ToParquet(&element);
-    elements_->push_back(element);
-
-    if (node->is_group()) {
-      const GroupNode* group_node = static_cast<const GroupNode*>(node);
-      for (int i = 0; i < group_node->field_count(); ++i) {
-        group_node->field(i)->VisitConst(this);
-      }
-    }
-  }
-
- private:
-  std::vector<format::SchemaElement>* elements_;
-};
-
-SchemaFlattener::SchemaFlattener(const GroupNode* schema,
-                                 std::vector<format::SchemaElement>* out)
-    : root_(schema), elements_(out) {}
-
-void SchemaFlattener::Flatten() {
-  SchemaVisitor visitor(elements_);
-  root_->VisitConst(&visitor);
-}
-
-// ----------------------------------------------------------------------
-// Schema printing
-
-class SchemaPrinter : public Node::ConstVisitor {
- public:
-  explicit SchemaPrinter(std::ostream& stream, int indent_width)
-      : stream_(stream), indent_(0), indent_width_(2) {}
-
-  void Visit(const Node* node) override;
-
- private:
-  void Visit(const PrimitiveNode* node);
-  void Visit(const GroupNode* node);
-
-  void Indent();
-
-  std::ostream& stream_;
-
-  int indent_;
-  int indent_width_;
-};
-
-static void PrintRepLevel(Repetition::type repetition, std::ostream& stream) {
-  switch (repetition) {
-    case Repetition::REQUIRED:
-      stream << "required";
-      break;
-    case Repetition::OPTIONAL:
-      stream << "optional";
-      break;
-    case Repetition::REPEATED:
-      stream << "repeated";
-      break;
-    default:
-      break;
-  }
-}
-
-static void PrintType(const PrimitiveNode* node, std::ostream& stream) {
-  switch (node->physical_type()) {
-    case Type::BOOLEAN:
-      stream << "boolean";
-      break;
-    case Type::INT32:
-      stream << "int32";
-      break;
-    case Type::INT64:
-      stream << "int64";
-      break;
-    case Type::INT96:
-      stream << "int96";
-      break;
-    case Type::FLOAT:
-      stream << "float";
-      break;
-    case Type::DOUBLE:
-      stream << "double";
-      break;
-    case Type::BYTE_ARRAY:
-      stream << "binary";
-      break;
-    case Type::FIXED_LEN_BYTE_ARRAY:
-      stream << "fixed_len_byte_array(" << node->type_length() << ")";
-      break;
-    default:
-      break;
-  }
-}
-
-static void PrintLogicalType(const PrimitiveNode* node, std::ostream& stream) {
-  auto lt = node->logical_type();
-  if (lt == LogicalType::DECIMAL) {
-    stream << " (" << LogicalTypeToString(lt) << "(" << node->decimal_metadata().precision
-           << "," << node->decimal_metadata().scale << "))";
-  } else if (lt != LogicalType::NONE) {
-    stream << " (" << LogicalTypeToString(lt) << ")";
-  }
-}
-
-void SchemaPrinter::Visit(const PrimitiveNode* node) {
-  PrintRepLevel(node->repetition(), stream_);
-  stream_ << " ";
-  PrintType(node, stream_);
-  stream_ << " " << node->name();
-  PrintLogicalType(node, stream_);
-  stream_ << ";" << std::endl;
-}
-
-void SchemaPrinter::Visit(const GroupNode* node) {
-  if (!node->parent()) {
-    stream_ << "message " << node->name() << " {" << std::endl;
-  } else {
-    PrintRepLevel(node->repetition(), stream_);
-    stream_ << " group " << node->name();
-    auto lt = node->logical_type();
-    if (lt != LogicalType::NONE) {
-      stream_ << " (" << LogicalTypeToString(lt) << ")";
-    }
-    stream_ << " {" << std::endl;
-  }
-
-  indent_ += indent_width_;
-  for (int i = 0; i < node->field_count(); ++i) {
-    node->field(i)->VisitConst(this);
-  }
-  indent_ -= indent_width_;
-  Indent();
-  stream_ << "}" << std::endl;
-}
-
-void SchemaPrinter::Indent() {
-  if (indent_ > 0) {
-    std::string spaces(indent_, ' ');
-    stream_ << spaces;
-  }
-}
-
-void SchemaPrinter::Visit(const Node* node) {
-  Indent();
-  if (node->is_group()) {
-    Visit(static_cast<const GroupNode*>(node));
-  } else {
-    // Primitive
-    Visit(static_cast<const PrimitiveNode*>(node));
-  }
-}
-
-void PrintSchema(const Node* schema, std::ostream& stream, int indent_width) {
-  SchemaPrinter printer(stream, indent_width);
-  printer.Visit(schema);
-}
-
-}  // namespace schema
-
-using schema::ColumnPath;
-using schema::GroupNode;
-using schema::Node;
-using schema::NodePtr;
-using schema::PrimitiveNode;
-
-void SchemaDescriptor::Init(std::unique_ptr<schema::Node> schema) {
-  Init(NodePtr(schema.release()));
-}
-
-class SchemaUpdater : public Node::Visitor {
- public:
-  explicit SchemaUpdater(const std::vector<ColumnOrder>& column_orders)
-      : column_orders_(column_orders), leaf_count_(0) {}
-
-  void Visit(Node* node) override {
-    if (node->is_group()) {
-      GroupNode* group_node = static_cast<GroupNode*>(node);
-      for (int i = 0; i < group_node->field_count(); ++i) {
-        group_node->field(i)->Visit(this);
-      }
-    } else {  // leaf node
-      PrimitiveNode* leaf_node = static_cast<PrimitiveNode*>(node);
-      leaf_node->SetColumnOrder(column_orders_[leaf_count_++]);
-    }
-  }
-
- private:
-  const std::vector<ColumnOrder>& column_orders_;
-  int leaf_count_;
-};
-
-void SchemaDescriptor::updateColumnOrders(const std::vector<ColumnOrder>& column_orders) {
-  if (static_cast<int>(column_orders.size()) != num_columns()) {
-    throw ParquetException("Malformed schema: not enough ColumnOrder values");
-  }
-  SchemaUpdater visitor(column_orders);
-  const_cast<GroupNode*>(group_node_)->Visit(&visitor);
-}
-
-void SchemaDescriptor::Init(const NodePtr& schema) {
-  schema_ = schema;
-
-  if (!schema_->is_group()) {
-    throw ParquetException("Must initialize with a schema group");
-  }
-
-  group_node_ = static_cast<const GroupNode*>(schema_.get());
-  leaves_.clear();
-
-  for (int i = 0; i < group_node_->field_count(); ++i) {
-    BuildTree(group_node_->field(i), 0, 0, group_node_->field(i));
-  }
-}
-
-bool SchemaDescriptor::Equals(const SchemaDescriptor& other) const {
-  if (this->num_columns() != other.num_columns()) {
-    return false;
-  }
-
-  for (int i = 0; i < this->num_columns(); ++i) {
-    if (!this->Column(i)->Equals(*other.Column(i))) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
-void SchemaDescriptor::BuildTree(const NodePtr& node, int16_t max_def_level,
-                                 int16_t max_rep_level, const NodePtr& base) {
-  if (node->is_optional()) {
-    ++max_def_level;
-  } else if (node->is_repeated()) {
-    // Repeated fields add a definition level. This is used to distinguish
-    // between an empty list and a list with an item in it.
-    ++max_rep_level;
-    ++max_def_level;
-  }
-
-  // Now, walk the schema and create a ColumnDescriptor for each leaf node
-  if (node->is_group()) {
-    const GroupNode* group = static_cast<const GroupNode*>(node.get());
-    for (int i = 0; i < group->field_count(); ++i) {
-      BuildTree(group->field(i), max_def_level, max_rep_level, base);
-    }
-  } else {
-    // Primitive node, append to leaves
-    leaves_.push_back(ColumnDescriptor(node, max_def_level, max_rep_level, this));
-    leaf_to_base_.emplace(static_cast<int>(leaves_.size()) - 1, base);
-    leaf_to_idx_.emplace(node->path()->ToDotString(),
-                         static_cast<int>(leaves_.size()) - 1);
-  }
-}
-
-ColumnDescriptor::ColumnDescriptor(const schema::NodePtr& node,
-                                   int16_t max_definition_level,
-                                   int16_t max_repetition_level,
-                                   const SchemaDescriptor* schema_descr)
-    : node_(node),
-      max_definition_level_(max_definition_level),
-      max_repetition_level_(max_repetition_level) {
-  if (!node_->is_primitive()) {
-    throw ParquetException("Must be a primitive type");
-  }
-  primitive_node_ = static_cast<const PrimitiveNode*>(node_.get());
-}
-
-bool ColumnDescriptor::Equals(const ColumnDescriptor& other) const {
-  return primitive_node_->Equals(other.primitive_node_) &&
-         max_repetition_level() == other.max_repetition_level() &&
-         max_definition_level() == other.max_definition_level();
-}
-
-const ColumnDescriptor* SchemaDescriptor::Column(int i) const {
-  DCHECK(i >= 0 && i < static_cast<int>(leaves_.size()));
-  return &leaves_[i];
-}
-
-int SchemaDescriptor::ColumnIndex(const std::string& node_path) const {
-  auto search = leaf_to_idx_.find(node_path);
-  if (search == leaf_to_idx_.end()) {
-    // Not found
-    return -1;
-  }
-  return search->second;
-}
-
-int SchemaDescriptor::ColumnIndex(const Node& node) const {
-  auto search = leaf_to_idx_.equal_range(node.path()->ToDotString());
-  for (auto it = search.first; it != search.second; ++it) {
-    const int idx = it->second;
-    if (&node == Column(idx)->schema_node().get()) {
-      return idx;
-    }
-  }
-  return -1;
-}
-
-const schema::Node* SchemaDescriptor::GetColumnRoot(int i) const {
-  DCHECK(i >= 0 && i < static_cast<int>(leaves_.size()));
-  return leaf_to_base_.find(i)->second.get();
-}
-
-std::string SchemaDescriptor::ToString() const {
-  std::ostringstream ss;
-  PrintSchema(schema_.get(), ss);
-  return ss.str();
-}
-
-int ColumnDescriptor::type_scale() const {
-  return primitive_node_->decimal_metadata().scale;
-}
-
-int ColumnDescriptor::type_precision() const {
-  return primitive_node_->decimal_metadata().precision;
-}
-
-int ColumnDescriptor::type_length() const { return primitive_node_->type_length(); }
-
-const std::shared_ptr<ColumnPath> ColumnDescriptor::path() const {
-  return primitive_node_->path();
-}
-
-}  // namespace parquet
diff --git a/src/parquet/schema.h b/src/parquet/schema.h
deleted file mode 100644
index 1a94ed1..0000000
--- a/src/parquet/schema.h
+++ /dev/null
@@ -1,452 +0,0 @@
-// 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.
-
-// This module contains the logical parquet-cpp types (independent of Thrift
-// structures), schema nodes, and related type tools
-
-#ifndef PARQUET_SCHEMA_TYPES_H
-#define PARQUET_SCHEMA_TYPES_H
-
-#include <cstdint>
-#include <memory>
-#include <ostream>
-#include <string>
-#include <unordered_map>
-#include <vector>
-
-#include "parquet/types.h"
-#include "parquet/util/macros.h"
-#include "parquet/util/visibility.h"
-
-namespace parquet {
-
-class SchemaDescriptor;
-
-namespace schema {
-
-class Node;
-
-// List encodings: using the terminology from Impala to define different styles
-// of representing logical lists (a.k.a. ARRAY types) in Parquet schemas. Since
-// the converted type named in the Parquet metadata is ConvertedType::LIST we
-// use that terminology here. It also helps distinguish from the *_ARRAY
-// primitive types.
-//
-// One-level encoding: Only allows required lists with required cells
-//   repeated value_type name
-//
-// Two-level encoding: Enables optional lists with only required cells
-//   <required/optional> group list
-//     repeated value_type item
-//
-// Three-level encoding: Enables optional lists with optional cells
-//   <required/optional> group bag
-//     repeated group list
-//       <required/optional> value_type item
-//
-// 2- and 1-level encoding are respectively equivalent to 3-level encoding with
-// the non-repeated nodes set to required.
-//
-// The "official" encoding recommended in the Parquet spec is the 3-level, and
-// we use that as the default when creating list types. For semantic completeness
-// we allow the other two. Since all types of encodings will occur "in the
-// wild" we need to be able to interpret the associated definition levels in
-// the context of the actual encoding used in the file.
-//
-// NB: Some Parquet writers may not set ConvertedType::LIST on the repeated
-// SchemaElement, which could make things challenging if we are trying to infer
-// that a sequence of nodes semantically represents an array according to one
-// of these encodings (versus a struct containing an array). We should refuse
-// the temptation to guess, as they say.
-struct ListEncoding {
-  enum type { ONE_LEVEL, TWO_LEVEL, THREE_LEVEL };
-};
-
-struct DecimalMetadata {
-  bool isset;
-  int32_t scale;
-  int32_t precision;
-};
-
-class PARQUET_EXPORT ColumnPath {
- public:
-  ColumnPath() : path_() {}
-  explicit ColumnPath(const std::vector<std::string>& path) : path_(path) {}
-  explicit ColumnPath(std::vector<std::string>&& path) : path_(path) {}
-
-  static std::shared_ptr<ColumnPath> FromDotString(const std::string& dotstring);
-  static std::shared_ptr<ColumnPath> FromNode(const Node& node);
-
-  std::shared_ptr<ColumnPath> extend(const std::string& node_name) const;
-  std::string ToDotString() const;
-  const std::vector<std::string>& ToDotVector() const;
-
- protected:
-  std::vector<std::string> path_;
-};
-
-class GroupNode;
-
-// Base class for logical schema types. A type has a name, repetition level,
-// and optionally a logical type (ConvertedType in Parquet metadata parlance)
-class PARQUET_EXPORT Node {
- public:
-  enum type { PRIMITIVE, GROUP };
-
-  Node(Node::type type, const std::string& name, Repetition::type repetition,
-       LogicalType::type logical_type = LogicalType::NONE, int id = -1)
-      : type_(type),
-        name_(name),
-        repetition_(repetition),
-        logical_type_(logical_type),
-        id_(id),
-        parent_(nullptr) {}
-
-  virtual ~Node() {}
-
-  bool is_primitive() const { return type_ == Node::PRIMITIVE; }
-
-  bool is_group() const { return type_ == Node::GROUP; }
-
-  bool is_optional() const { return repetition_ == Repetition::OPTIONAL; }
-
-  bool is_repeated() const { return repetition_ == Repetition::REPEATED; }
-
-  bool is_required() const { return repetition_ == Repetition::REQUIRED; }
-
-  virtual bool Equals(const Node* other) const = 0;
-
-  const std::string& name() const { return name_; }
-
-  Node::type node_type() const { return type_; }
-
-  Repetition::type repetition() const { return repetition_; }
-
-  LogicalType::type logical_type() const { return logical_type_; }
-
-  int id() const { return id_; }
-
-  const Node* parent() const { return parent_; }
-
-  const std::shared_ptr<ColumnPath> path() const;
-
-  // ToParquet returns an opaque void* to avoid exporting
-  // parquet::SchemaElement into the public API
-  virtual void ToParquet(void* opaque_element) const = 0;
-
-  // Node::Visitor abstract class for walking schemas with the visitor pattern
-  class Visitor {
-   public:
-    virtual ~Visitor() {}
-
-    virtual void Visit(Node* node) = 0;
-  };
-  class ConstVisitor {
-   public:
-    virtual ~ConstVisitor() {}
-
-    virtual void Visit(const Node* node) = 0;
-  };
-
-  virtual void Visit(Visitor* visitor) = 0;
-  virtual void VisitConst(ConstVisitor* visitor) const = 0;
-
- protected:
-  friend class GroupNode;
-
-  Node::type type_;
-  std::string name_;
-  Repetition::type repetition_;
-  LogicalType::type logical_type_;
-  int id_;
-  // Nodes should not be shared, they have a single parent.
-  const Node* parent_;
-
-  bool EqualsInternal(const Node* other) const;
-  void SetParent(const Node* p_parent);
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(Node);
-};
-
-// Save our breath all over the place with these typedefs
-typedef std::shared_ptr<Node> NodePtr;
-typedef std::vector<NodePtr> NodeVector;
-
-// A type that is one of the primitive Parquet storage types. In addition to
-// the other type metadata (name, repetition level, logical type), also has the
-// physical storage type and their type-specific metadata (byte width, decimal
-// parameters)
-class PARQUET_EXPORT PrimitiveNode : public Node {
- public:
-  // FromParquet accepts an opaque void* to avoid exporting
-  // parquet::SchemaElement into the public API
-  static std::unique_ptr<Node> FromParquet(const void* opaque_element, int id);
-
-  static inline NodePtr Make(const std::string& name, Repetition::type repetition,
-                             Type::type type,
-                             LogicalType::type logical_type = LogicalType::NONE,
-                             int length = -1, int precision = -1, int scale = -1) {
-    return NodePtr(new PrimitiveNode(name, repetition, type, logical_type, length,
-                                     precision, scale));
-  }
-
-  bool Equals(const Node* other) const override;
-
-  Type::type physical_type() const { return physical_type_; }
-
-  ColumnOrder column_order() const { return column_order_; }
-
-  void SetColumnOrder(ColumnOrder column_order) { column_order_ = column_order; }
-
-  int32_t type_length() const { return type_length_; }
-
-  const DecimalMetadata& decimal_metadata() const { return decimal_metadata_; }
-
-  void ToParquet(void* opaque_element) const override;
-  void Visit(Visitor* visitor) override;
-  void VisitConst(ConstVisitor* visitor) const override;
-
- private:
-  PrimitiveNode(const std::string& name, Repetition::type repetition, Type::type type,
-                LogicalType::type logical_type = LogicalType::NONE, int length = -1,
-                int precision = -1, int scale = -1, int id = -1);
-
-  Type::type physical_type_;
-  int32_t type_length_;
-  DecimalMetadata decimal_metadata_;
-  ColumnOrder column_order_;
-
-  // For FIXED_LEN_BYTE_ARRAY
-  void SetTypeLength(int32_t length) { type_length_ = length; }
-
-  // For Decimal logical type: Precision and scale
-  void SetDecimalMetadata(int32_t scale, int32_t precision) {
-    decimal_metadata_.scale = scale;
-    decimal_metadata_.precision = precision;
-  }
-
-  bool EqualsInternal(const PrimitiveNode* other) const;
-
-  FRIEND_TEST(TestPrimitiveNode, Attrs);
-  FRIEND_TEST(TestPrimitiveNode, Equals);
-  FRIEND_TEST(TestPrimitiveNode, PhysicalLogicalMapping);
-  FRIEND_TEST(TestPrimitiveNode, FromParquet);
-};
-
-class PARQUET_EXPORT GroupNode : public Node {
- public:
-  // Like PrimitiveNode, GroupNode::FromParquet accepts an opaque void* to avoid exporting
-  // parquet::SchemaElement into the public API
-  static std::unique_ptr<Node> FromParquet(const void* opaque_element, int id,
-                                           const NodeVector& fields);
-
-  static inline NodePtr Make(const std::string& name, Repetition::type repetition,
-                             const NodeVector& fields,
-                             LogicalType::type logical_type = LogicalType::NONE) {
-    return NodePtr(new GroupNode(name, repetition, fields, logical_type));
-  }
-
-  bool Equals(const Node* other) const override;
-
-  NodePtr field(int i) const { return fields_[i]; }
-  // Get the index of a field by its name, or negative value if not found.
-  // If several fields share the same name, it is unspecified which one
-  // is returned.
-  int FieldIndex(const std::string& name) const;
-  // Get the index of a field by its node, or negative value if not found.
-  int FieldIndex(const Node& node) const;
-
-  int field_count() const { return static_cast<int>(fields_.size()); }
-
-  void ToParquet(void* opaque_element) const override;
-  void Visit(Visitor* visitor) override;
-  void VisitConst(ConstVisitor* visitor) const override;
-
- private:
-  GroupNode(const std::string& name, Repetition::type repetition,
-            const NodeVector& fields, LogicalType::type logical_type = LogicalType::NONE,
-            int id = -1)
-      : Node(Node::GROUP, name, repetition, logical_type, id), fields_(fields) {
-    field_name_to_idx_.clear();
-    auto field_idx = 0;
-    for (NodePtr& field : fields_) {
-      field->SetParent(this);
-      field_name_to_idx_.emplace(field->name(), field_idx++);
-    }
-  }
-
-  NodeVector fields_;
-  bool EqualsInternal(const GroupNode* other) const;
-
-  // Mapping between field name to the field index
-  std::unordered_multimap<std::string, int> field_name_to_idx_;
-
-  FRIEND_TEST(TestGroupNode, Attrs);
-  FRIEND_TEST(TestGroupNode, Equals);
-  FRIEND_TEST(TestGroupNode, FieldIndex);
-  FRIEND_TEST(TestGroupNode, FieldIndexDuplicateName);
-};
-
-// ----------------------------------------------------------------------
-// Convenience primitive type factory functions
-
-#define PRIMITIVE_FACTORY(FuncName, TYPE)                                              \
-  static inline NodePtr FuncName(const std::string& name,                              \
-                                 Repetition::type repetition = Repetition::OPTIONAL) { \
-    return PrimitiveNode::Make(name, repetition, Type::TYPE);                          \
-  }
-
-PRIMITIVE_FACTORY(Boolean, BOOLEAN);
-PRIMITIVE_FACTORY(Int32, INT32);
-PRIMITIVE_FACTORY(Int64, INT64);
-PRIMITIVE_FACTORY(Int96, INT96);
-PRIMITIVE_FACTORY(Float, FLOAT);
-PRIMITIVE_FACTORY(Double, DOUBLE);
-PRIMITIVE_FACTORY(ByteArray, BYTE_ARRAY);
-
-void PARQUET_EXPORT PrintSchema(const schema::Node* schema, std::ostream& stream,
-                                int indent_width = 2);
-
-}  // namespace schema
-
-// The ColumnDescriptor encapsulates information necessary to interpret
-// primitive column data in the context of a particular schema. We have to
-// examine the node structure of a column's path to the root in the schema tree
-// to be able to reassemble the nested structure from the repetition and
-// definition levels.
-class PARQUET_EXPORT ColumnDescriptor {
- public:
-  ColumnDescriptor(const schema::NodePtr& node, int16_t max_definition_level,
-                   int16_t max_repetition_level,
-                   const SchemaDescriptor* schema_descr = nullptr);
-
-  bool Equals(const ColumnDescriptor& other) const;
-
-  int16_t max_definition_level() const { return max_definition_level_; }
-
-  int16_t max_repetition_level() const { return max_repetition_level_; }
-
-  Type::type physical_type() const { return primitive_node_->physical_type(); }
-
-  LogicalType::type logical_type() const { return primitive_node_->logical_type(); }
-
-  ColumnOrder column_order() const { return primitive_node_->column_order(); }
-
-  SortOrder::type sort_order() const {
-    return GetSortOrder(logical_type(), physical_type());
-  }
-
-  const std::string& name() const { return primitive_node_->name(); }
-
-  const std::shared_ptr<schema::ColumnPath> path() const;
-
-  const schema::NodePtr& schema_node() const { return node_; }
-
-  int type_length() const;
-
-  int type_precision() const;
-
-  int type_scale() const;
-
- private:
-  schema::NodePtr node_;
-  const schema::PrimitiveNode* primitive_node_;
-
-  int16_t max_definition_level_;
-  int16_t max_repetition_level_;
-};
-
-// Container for the converted Parquet schema with a computed information from
-// the schema analysis needed for file reading
-//
-// * Column index to Node
-// * Max repetition / definition levels for each primitive node
-//
-// The ColumnDescriptor objects produced by this class can be used to assist in
-// the reconstruction of fully materialized data structures from the
-// repetition-definition level encoding of nested data
-//
-// TODO(wesm): this object can be recomputed from a Schema
-class PARQUET_EXPORT SchemaDescriptor {
- public:
-  SchemaDescriptor() {}
-  ~SchemaDescriptor() {}
-
-  // Analyze the schema
-  void Init(std::unique_ptr<schema::Node> schema);
-  void Init(const schema::NodePtr& schema);
-
-  const ColumnDescriptor* Column(int i) const;
-
-  // Get the index of a column by its dotstring path, or negative value if not found.
-  // If several columns share the same dotstring path, it is unspecified which one
-  // is returned.
-  int ColumnIndex(const std::string& node_path) const;
-  // Get the index of a column by its node, or negative value if not found.
-  int ColumnIndex(const schema::Node& node) const;
-
-  bool Equals(const SchemaDescriptor& other) const;
-
-  // The number of physical columns appearing in the file
-  int num_columns() const { return static_cast<int>(leaves_.size()); }
-
-  const schema::NodePtr& schema_root() const { return schema_; }
-
-  const schema::GroupNode* group_node() const { return group_node_; }
-
-  // Returns the root (child of the schema root) node of the leaf(column) node
-  const schema::Node* GetColumnRoot(int i) const;
-
-  const std::string& name() const { return group_node_->name(); }
-
-  std::string ToString() const;
-
-  void updateColumnOrders(const std::vector<ColumnOrder>& column_orders);
-
- private:
-  friend class ColumnDescriptor;
-
-  // Root Node
-  schema::NodePtr schema_;
-  // Root Node
-  const schema::GroupNode* group_node_;
-
-  void BuildTree(const schema::NodePtr& node, int16_t max_def_level,
-                 int16_t max_rep_level, const schema::NodePtr& base);
-
-  // Result of leaf node / tree analysis
-  std::vector<ColumnDescriptor> leaves_;
-
-  // Mapping between leaf nodes and root group of leaf (first node
-  // below the schema's root group)
-  //
-  // For example, the leaf `a.b.c.d` would have a link back to `a`
-  //
-  // -- a  <------
-  // -- -- b     |
-  // -- -- -- c  |
-  // -- -- -- -- d
-  std::unordered_map<int, const schema::NodePtr> leaf_to_base_;
-
-  // Mapping between ColumnPath DotString to the leaf index
-  std::unordered_multimap<std::string, int> leaf_to_idx_;
-};
-
-}  // namespace parquet
-
-#endif  // PARQUET_SCHEMA_TYPES_H
diff --git a/src/parquet/statistics-test.cc b/src/parquet/statistics-test.cc
deleted file mode 100644
index d2ecede..0000000
--- a/src/parquet/statistics-test.cc
+++ /dev/null
@@ -1,782 +0,0 @@
-// 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.
-
-#include <gtest/gtest.h>
-
-#include <algorithm>
-#include <array>
-#include <cstdint>
-#include <cstring>
-#include <memory>
-#include <vector>
-
-#include "parquet/column_reader.h"
-#include "parquet/column_writer.h"
-#include "parquet/file_reader.h"
-#include "parquet/file_writer.h"
-#include "parquet/schema.h"
-#include "parquet/statistics.h"
-#include "parquet/test-specialization.h"
-#include "parquet/test-util.h"
-#include "parquet/thrift.h"
-#include "parquet/types.h"
-#include "parquet/util/memory.h"
-
-using arrow::default_memory_pool;
-using arrow::MemoryPool;
-
-namespace parquet {
-
-using schema::GroupNode;
-using schema::NodePtr;
-using schema::PrimitiveNode;
-
-namespace test {
-
-template <typename TestType>
-class TestRowGroupStatistics : public PrimitiveTypedTest<TestType> {
- public:
-  using T = typename TestType::c_type;
-  using TypedStats = TypedRowGroupStatistics<TestType>;
-
-  std::vector<T> GetDeepCopy(
-      const std::vector<T>&);  // allocates new memory for FLBA/ByteArray
-
-  T* GetValuesPointer(std::vector<T>&);
-  void DeepFree(std::vector<T>&);
-
-  void TestMinMaxEncode() {
-    this->GenerateData(1000);
-
-    TypedStats statistics1(this->schema_.Column(0));
-    statistics1.Update(this->values_ptr_, this->values_.size(), 0);
-    std::string encoded_min = statistics1.EncodeMin();
-    std::string encoded_max = statistics1.EncodeMax();
-
-    TypedStats statistics2(this->schema_.Column(0), encoded_min, encoded_max,
-                           this->values_.size(), 0, 0, true);
-
-    TypedStats statistics3(this->schema_.Column(0));
-    std::vector<uint8_t> valid_bits(
-        BitUtil::BytesForBits(static_cast<uint32_t>(this->values_.size())) + 1, 255);
-    statistics3.UpdateSpaced(this->values_ptr_, valid_bits.data(), 0,
-                             this->values_.size(), 0);
-    std::string encoded_min_spaced = statistics3.EncodeMin();
-    std::string encoded_max_spaced = statistics3.EncodeMax();
-
-    ASSERT_EQ(encoded_min, statistics2.EncodeMin());
-    ASSERT_EQ(encoded_max, statistics2.EncodeMax());
-    ASSERT_EQ(statistics1.min(), statistics2.min());
-    ASSERT_EQ(statistics1.max(), statistics2.max());
-    ASSERT_EQ(encoded_min_spaced, statistics2.EncodeMin());
-    ASSERT_EQ(encoded_max_spaced, statistics2.EncodeMax());
-    ASSERT_EQ(statistics3.min(), statistics2.min());
-    ASSERT_EQ(statistics3.max(), statistics2.max());
-  }
-
-  void TestReset() {
-    this->GenerateData(1000);
-
-    TypedStats statistics(this->schema_.Column(0));
-    statistics.Update(this->values_ptr_, this->values_.size(), 0);
-    ASSERT_EQ(this->values_.size(), statistics.num_values());
-
-    statistics.Reset();
-    ASSERT_EQ(0, statistics.null_count());
-    ASSERT_EQ(0, statistics.num_values());
-    ASSERT_EQ("", statistics.EncodeMin());
-    ASSERT_EQ("", statistics.EncodeMax());
-  }
-
-  void TestMerge() {
-    int num_null[2];
-    random_numbers(2, 42, 0, 100, num_null);
-
-    TypedStats statistics1(this->schema_.Column(0));
-    this->GenerateData(1000);
-    statistics1.Update(this->values_ptr_, this->values_.size() - num_null[0],
-                       num_null[0]);
-
-    TypedStats statistics2(this->schema_.Column(0));
-    this->GenerateData(1000);
-    statistics2.Update(this->values_ptr_, this->values_.size() - num_null[1],
-                       num_null[1]);
-
-    TypedStats total(this->schema_.Column(0));
-    total.Merge(statistics1);
-    total.Merge(statistics2);
-
-    ASSERT_EQ(num_null[0] + num_null[1], total.null_count());
-    ASSERT_EQ(this->values_.size() * 2 - num_null[0] - num_null[1], total.num_values());
-    ASSERT_EQ(total.min(), std::min(statistics1.min(), statistics2.min()));
-    ASSERT_EQ(total.max(), std::max(statistics1.max(), statistics2.max()));
-  }
-
-  void TestFullRoundtrip(int64_t num_values, int64_t null_count) {
-    this->GenerateData(num_values);
-
-    // compute statistics for the whole batch
-    TypedStats expected_stats(this->schema_.Column(0));
-    expected_stats.Update(this->values_ptr_, num_values - null_count, null_count);
-
-    auto sink = std::make_shared<InMemoryOutputStream>();
-    auto gnode = std::static_pointer_cast<GroupNode>(this->node_);
-    std::shared_ptr<WriterProperties> writer_properties =
-        WriterProperties::Builder().enable_statistics("column")->build();
-    auto file_writer = ParquetFileWriter::Open(sink, gnode, writer_properties);
-    auto row_group_writer = file_writer->AppendRowGroup();
-    auto column_writer =
-        static_cast<TypedColumnWriter<TestType>*>(row_group_writer->NextColumn());
-
-    // simulate the case when data comes from multiple buffers,
-    // in which case special care is necessary for FLBA/ByteArray types
-    for (int i = 0; i < 2; i++) {
-      int64_t batch_num_values = i ? num_values - num_values / 2 : num_values / 2;
-      int64_t batch_null_count = i ? null_count : 0;
-      DCHECK(null_count <= num_values);  // avoid too much headache
-      std::vector<int16_t> definition_levels(batch_null_count, 0);
-      definition_levels.insert(definition_levels.end(),
-                               batch_num_values - batch_null_count, 1);
-      auto beg = this->values_.begin() + i * num_values / 2;
-      auto end = beg + batch_num_values;
-      std::vector<T> batch = GetDeepCopy(std::vector<T>(beg, end));
-      T* batch_values_ptr = GetValuesPointer(batch);
-      column_writer->WriteBatch(batch_num_values, definition_levels.data(), nullptr,
-                                batch_values_ptr);
-      DeepFree(batch);
-    }
-    column_writer->Close();
-    row_group_writer->Close();
-    file_writer->Close();
-
-    auto buffer = sink->GetBuffer();
-    auto source = std::make_shared<::arrow::io::BufferReader>(buffer);
-    auto file_reader = ParquetFileReader::Open(source);
-    auto rg_reader = file_reader->RowGroup(0);
-    auto column_chunk = rg_reader->metadata()->ColumnChunk(0);
-    if (!column_chunk->is_stats_set()) return;
-    std::shared_ptr<RowGroupStatistics> stats = column_chunk->statistics();
-    // check values after serialization + deserialization
-    ASSERT_EQ(null_count, stats->null_count());
-    ASSERT_EQ(num_values - null_count, stats->num_values());
-    ASSERT_EQ(expected_stats.EncodeMin(), stats->EncodeMin());
-    ASSERT_EQ(expected_stats.EncodeMax(), stats->EncodeMax());
-  }
-};
-
-template <typename TestType>
-typename TestType::c_type* TestRowGroupStatistics<TestType>::GetValuesPointer(
-    std::vector<typename TestType::c_type>& values) {
-  return values.data();
-}
-
-template <>
-bool* TestRowGroupStatistics<BooleanType>::GetValuesPointer(std::vector<bool>& values) {
-  static std::vector<uint8_t> bool_buffer;
-  bool_buffer.clear();
-  bool_buffer.resize(values.size());
-  std::copy(values.begin(), values.end(), bool_buffer.begin());
-  return reinterpret_cast<bool*>(bool_buffer.data());
-}
-
-template <typename TestType>
-typename std::vector<typename TestType::c_type>
-TestRowGroupStatistics<TestType>::GetDeepCopy(
-    const std::vector<typename TestType::c_type>& values) {
-  return values;
-}
-
-template <>
-std::vector<FLBA> TestRowGroupStatistics<FLBAType>::GetDeepCopy(
-    const std::vector<FLBA>& values) {
-  std::vector<FLBA> copy;
-  MemoryPool* pool = ::arrow::default_memory_pool();
-  for (const FLBA& flba : values) {
-    uint8_t* ptr;
-    PARQUET_THROW_NOT_OK(pool->Allocate(FLBA_LENGTH, &ptr));
-    memcpy(ptr, flba.ptr, FLBA_LENGTH);
-    copy.emplace_back(ptr);
-  }
-  return copy;
-}
-
-template <>
-std::vector<ByteArray> TestRowGroupStatistics<ByteArrayType>::GetDeepCopy(
-    const std::vector<ByteArray>& values) {
-  std::vector<ByteArray> copy;
-  MemoryPool* pool = default_memory_pool();
-  for (const ByteArray& ba : values) {
-    uint8_t* ptr;
-    PARQUET_THROW_NOT_OK(pool->Allocate(ba.len, &ptr));
-    memcpy(ptr, ba.ptr, ba.len);
-    copy.emplace_back(ba.len, ptr);
-  }
-  return copy;
-}
-
-template <typename TestType>
-void TestRowGroupStatistics<TestType>::DeepFree(
-    std::vector<typename TestType::c_type>& values) {}
-
-template <>
-void TestRowGroupStatistics<FLBAType>::DeepFree(std::vector<FLBA>& values) {
-  MemoryPool* pool = default_memory_pool();
-  for (FLBA& flba : values) {
-    auto ptr = const_cast<uint8_t*>(flba.ptr);
-    memset(ptr, 0, FLBA_LENGTH);
-    pool->Free(ptr, FLBA_LENGTH);
-  }
-}
-
-template <>
-void TestRowGroupStatistics<ByteArrayType>::DeepFree(std::vector<ByteArray>& values) {
-  MemoryPool* pool = default_memory_pool();
-  for (ByteArray& ba : values) {
-    auto ptr = const_cast<uint8_t*>(ba.ptr);
-    memset(ptr, 0, ba.len);
-    pool->Free(ptr, ba.len);
-  }
-}
-
-template <>
-void TestRowGroupStatistics<ByteArrayType>::TestMinMaxEncode() {
-  this->GenerateData(1000);
-  // Test that we encode min max strings correctly
-  TypedRowGroupStatistics<ByteArrayType> statistics1(this->schema_.Column(0));
-  statistics1.Update(this->values_ptr_, this->values_.size(), 0);
-  std::string encoded_min = statistics1.EncodeMin();
-  std::string encoded_max = statistics1.EncodeMax();
-
-  // encoded is same as unencoded
-  ASSERT_EQ(encoded_min,
-            std::string((const char*)statistics1.min().ptr, statistics1.min().len));
-  ASSERT_EQ(encoded_max,
-            std::string((const char*)statistics1.max().ptr, statistics1.max().len));
-
-  TypedRowGroupStatistics<ByteArrayType> statistics2(this->schema_.Column(0), encoded_min,
-                                                     encoded_max, this->values_.size(), 0,
-                                                     0, true);
-
-  ASSERT_EQ(encoded_min, statistics2.EncodeMin());
-  ASSERT_EQ(encoded_max, statistics2.EncodeMax());
-  ASSERT_EQ(statistics1.min(), statistics2.min());
-  ASSERT_EQ(statistics1.max(), statistics2.max());
-}
-
-using TestTypes = ::testing::Types<Int32Type, Int64Type, FloatType, DoubleType,
-                                   ByteArrayType, FLBAType, BooleanType>;
-
-TYPED_TEST_CASE(TestRowGroupStatistics, TestTypes);
-
-TYPED_TEST(TestRowGroupStatistics, MinMaxEncode) {
-  this->SetUpSchema(Repetition::REQUIRED);
-  ASSERT_NO_FATAL_FAILURE(this->TestMinMaxEncode());
-}
-
-TYPED_TEST(TestRowGroupStatistics, Reset) {
-  this->SetUpSchema(Repetition::OPTIONAL);
-  ASSERT_NO_FATAL_FAILURE(this->TestReset());
-}
-
-TYPED_TEST(TestRowGroupStatistics, FullRoundtrip) {
-  this->SetUpSchema(Repetition::OPTIONAL);
-  ASSERT_NO_FATAL_FAILURE(this->TestFullRoundtrip(100, 31));
-  ASSERT_NO_FATAL_FAILURE(this->TestFullRoundtrip(1000, 415));
-  ASSERT_NO_FATAL_FAILURE(this->TestFullRoundtrip(10000, 926));
-}
-
-template <typename TestType>
-class TestNumericRowGroupStatistics : public TestRowGroupStatistics<TestType> {};
-
-using NumericTypes = ::testing::Types<Int32Type, Int64Type, FloatType, DoubleType>;
-
-TYPED_TEST_CASE(TestNumericRowGroupStatistics, NumericTypes);
-
-TYPED_TEST(TestNumericRowGroupStatistics, Merge) {
-  this->SetUpSchema(Repetition::OPTIONAL);
-  ASSERT_NO_FATAL_FAILURE(this->TestMerge());
-}
-
-// Statistics are restricted for few types in older parquet version
-TEST(CorruptStatistics, Basics) {
-  ApplicationVersion version("parquet-mr version 1.8.0");
-  SchemaDescriptor schema;
-  schema::NodePtr node;
-  std::vector<schema::NodePtr> fields;
-  // Test Physical Types
-  fields.push_back(schema::PrimitiveNode::Make("col1", Repetition::OPTIONAL, Type::INT32,
-                                               LogicalType::NONE));
-  fields.push_back(schema::PrimitiveNode::Make("col2", Repetition::OPTIONAL,
-                                               Type::BYTE_ARRAY, LogicalType::NONE));
-  // Test Logical Types
-  fields.push_back(schema::PrimitiveNode::Make("col3", Repetition::OPTIONAL, Type::INT32,
-                                               LogicalType::DATE));
-  fields.push_back(schema::PrimitiveNode::Make("col4", Repetition::OPTIONAL, Type::INT32,
-                                               LogicalType::UINT_32));
-  fields.push_back(schema::PrimitiveNode::Make("col5", Repetition::OPTIONAL,
-                                               Type::FIXED_LEN_BYTE_ARRAY,
-                                               LogicalType::INTERVAL, 12));
-  fields.push_back(schema::PrimitiveNode::Make("col6", Repetition::OPTIONAL,
-                                               Type::BYTE_ARRAY, LogicalType::UTF8));
-  node = schema::GroupNode::Make("schema", Repetition::REQUIRED, fields);
-  schema.Init(node);
-
-  format::ColumnChunk col_chunk;
-  col_chunk.meta_data.__isset.statistics = true;
-  auto column_chunk1 = ColumnChunkMetaData::Make(
-      reinterpret_cast<const uint8_t*>(&col_chunk), schema.Column(0), &version);
-  ASSERT_TRUE(column_chunk1->is_stats_set());
-  auto column_chunk2 = ColumnChunkMetaData::Make(
-      reinterpret_cast<const uint8_t*>(&col_chunk), schema.Column(1), &version);
-  ASSERT_FALSE(column_chunk2->is_stats_set());
-  auto column_chunk3 = ColumnChunkMetaData::Make(
-      reinterpret_cast<const uint8_t*>(&col_chunk), schema.Column(2), &version);
-  ASSERT_TRUE(column_chunk3->is_stats_set());
-  auto column_chunk4 = ColumnChunkMetaData::Make(
-      reinterpret_cast<const uint8_t*>(&col_chunk), schema.Column(3), &version);
-  ASSERT_FALSE(column_chunk4->is_stats_set());
-  auto column_chunk5 = ColumnChunkMetaData::Make(
-      reinterpret_cast<const uint8_t*>(&col_chunk), schema.Column(4), &version);
-  ASSERT_FALSE(column_chunk5->is_stats_set());
-  auto column_chunk6 = ColumnChunkMetaData::Make(
-      reinterpret_cast<const uint8_t*>(&col_chunk), schema.Column(5), &version);
-  ASSERT_FALSE(column_chunk6->is_stats_set());
-}
-
-// Statistics for all types have no restrictions in newer parquet version
-TEST(CorrectStatistics, Basics) {
-  ApplicationVersion version("parquet-cpp version 1.3.0");
-  SchemaDescriptor schema;
-  schema::NodePtr node;
-  std::vector<schema::NodePtr> fields;
-  // Test Physical Types
-  fields.push_back(schema::PrimitiveNode::Make("col1", Repetition::OPTIONAL, Type::INT32,
-                                               LogicalType::NONE));
-  fields.push_back(schema::PrimitiveNode::Make("col2", Repetition::OPTIONAL,
-                                               Type::BYTE_ARRAY, LogicalType::NONE));
-  // Test Logical Types
-  fields.push_back(schema::PrimitiveNode::Make("col3", Repetition::OPTIONAL, Type::INT32,
-                                               LogicalType::DATE));
-  fields.push_back(schema::PrimitiveNode::Make("col4", Repetition::OPTIONAL, Type::INT32,
-                                               LogicalType::UINT_32));
-  fields.push_back(schema::PrimitiveNode::Make("col5", Repetition::OPTIONAL,
-                                               Type::FIXED_LEN_BYTE_ARRAY,
-                                               LogicalType::INTERVAL, 12));
-  fields.push_back(schema::PrimitiveNode::Make("col6", Repetition::OPTIONAL,
-                                               Type::BYTE_ARRAY, LogicalType::UTF8));
-  node = schema::GroupNode::Make("schema", Repetition::REQUIRED, fields);
-  schema.Init(node);
-
-  format::ColumnChunk col_chunk;
-  col_chunk.meta_data.__isset.statistics = true;
-  auto column_chunk1 = ColumnChunkMetaData::Make(
-      reinterpret_cast<const uint8_t*>(&col_chunk), schema.Column(0), &version);
-  ASSERT_TRUE(column_chunk1->is_stats_set());
-  auto column_chunk2 = ColumnChunkMetaData::Make(
-      reinterpret_cast<const uint8_t*>(&col_chunk), schema.Column(1), &version);
-  ASSERT_TRUE(column_chunk2->is_stats_set());
-  auto column_chunk3 = ColumnChunkMetaData::Make(
-      reinterpret_cast<const uint8_t*>(&col_chunk), schema.Column(2), &version);
-  ASSERT_TRUE(column_chunk3->is_stats_set());
-  auto column_chunk4 = ColumnChunkMetaData::Make(
-      reinterpret_cast<const uint8_t*>(&col_chunk), schema.Column(3), &version);
-  ASSERT_TRUE(column_chunk4->is_stats_set());
-  auto column_chunk5 = ColumnChunkMetaData::Make(
-      reinterpret_cast<const uint8_t*>(&col_chunk), schema.Column(4), &version);
-  ASSERT_FALSE(column_chunk5->is_stats_set());
-  auto column_chunk6 = ColumnChunkMetaData::Make(
-      reinterpret_cast<const uint8_t*>(&col_chunk), schema.Column(5), &version);
-  ASSERT_TRUE(column_chunk6->is_stats_set());
-}
-
-// Test SortOrder class
-static const int NUM_VALUES = 10;
-
-template <typename TestType>
-class TestStatistics : public ::testing::Test {
- public:
-  typedef typename TestType::c_type T;
-
-  void AddNodes(std::string name) {
-    fields_.push_back(schema::PrimitiveNode::Make(name, Repetition::REQUIRED,
-                                                  TestType::type_num, LogicalType::NONE));
-  }
-
-  void SetUpSchema() {
-    stats_.resize(fields_.size());
-    values_.resize(NUM_VALUES);
-    schema_ = std::static_pointer_cast<GroupNode>(
-        GroupNode::Make("Schema", Repetition::REQUIRED, fields_));
-
-    parquet_sink_ = std::make_shared<InMemoryOutputStream>();
-  }
-
-  void SetValues();
-
-  void WriteParquet() {
-    // Add writer properties
-    parquet::WriterProperties::Builder builder;
-    builder.compression(parquet::Compression::SNAPPY);
-    builder.created_by("parquet-cpp version 1.3.0");
-    std::shared_ptr<parquet::WriterProperties> props = builder.build();
-
-    // Create a ParquetFileWriter instance
-    auto file_writer = parquet::ParquetFileWriter::Open(parquet_sink_, schema_, props);
-
-    // Append a RowGroup with a specific number of rows.
-    auto rg_writer = file_writer->AppendRowGroup();
-
-    this->SetValues();
-
-    // Insert Values
-    for (int i = 0; i < static_cast<int>(fields_.size()); i++) {
-      auto column_writer =
-          static_cast<parquet::TypedColumnWriter<TestType>*>(rg_writer->NextColumn());
-      column_writer->WriteBatch(NUM_VALUES, nullptr, nullptr, values_.data());
-    }
-  }
-
-  void VerifyParquetStats() {
-    auto pbuffer = parquet_sink_->GetBuffer();
-
-    // Create a ParquetReader instance
-    std::unique_ptr<parquet::ParquetFileReader> parquet_reader =
-        parquet::ParquetFileReader::Open(
-            std::make_shared<arrow::io::BufferReader>(pbuffer));
-
-    // Get the File MetaData
-    std::shared_ptr<parquet::FileMetaData> file_metadata = parquet_reader->metadata();
-    std::shared_ptr<parquet::RowGroupMetaData> rg_metadata = file_metadata->RowGroup(0);
-    for (int i = 0; i < static_cast<int>(fields_.size()); i++) {
-      std::shared_ptr<parquet::ColumnChunkMetaData> cc_metadata =
-          rg_metadata->ColumnChunk(i);
-      ASSERT_EQ(stats_[i].min(), cc_metadata->statistics()->EncodeMin());
-      ASSERT_EQ(stats_[i].max(), cc_metadata->statistics()->EncodeMax());
-    }
-  }
-
- protected:
-  std::vector<T> values_;
-  std::vector<uint8_t> values_buf_;
-  std::vector<schema::NodePtr> fields_;
-  std::shared_ptr<schema::GroupNode> schema_;
-  std::shared_ptr<InMemoryOutputStream> parquet_sink_;
-  std::vector<EncodedStatistics> stats_;
-};
-
-using CompareTestTypes = ::testing::Types<Int32Type, Int64Type, FloatType, DoubleType,
-                                          ByteArrayType, FLBAType>;
-
-// TYPE::INT32
-template <>
-void TestStatistics<Int32Type>::AddNodes(std::string name) {
-  // UINT_32 logical type to set Unsigned Statistics
-  fields_.push_back(schema::PrimitiveNode::Make(name, Repetition::REQUIRED, Type::INT32,
-                                                LogicalType::UINT_32));
-  // INT_32 logical type to set Signed Statistics
-  fields_.push_back(schema::PrimitiveNode::Make(name, Repetition::REQUIRED, Type::INT32,
-                                                LogicalType::INT_32));
-}
-
-template <>
-void TestStatistics<Int32Type>::SetValues() {
-  for (int i = 0; i < NUM_VALUES; i++) {
-    values_[i] = i - 5;  // {-5, -4, -3, -2, -1, 0, 1, 2, 3, 4};
-  }
-
-  // Write UINT32 min/max values
-  stats_[0]
-      .set_min(std::string(reinterpret_cast<const char*>(&values_[5]), sizeof(T)))
-      .set_max(std::string(reinterpret_cast<const char*>(&values_[4]), sizeof(T)));
-
-  // Write INT32 min/max values
-  stats_[1]
-      .set_min(std::string(reinterpret_cast<const char*>(&values_[0]), sizeof(T)))
-      .set_max(std::string(reinterpret_cast<const char*>(&values_[9]), sizeof(T)));
-}
-
-// TYPE::INT64
-template <>
-void TestStatistics<Int64Type>::AddNodes(std::string name) {
-  // UINT_64 logical type to set Unsigned Statistics
-  fields_.push_back(schema::PrimitiveNode::Make(name, Repetition::REQUIRED, Type::INT64,
-                                                LogicalType::UINT_64));
-  // INT_64 logical type to set Signed Statistics
-  fields_.push_back(schema::PrimitiveNode::Make(name, Repetition::REQUIRED, Type::INT64,
-                                                LogicalType::INT_64));
-}
-
-template <>
-void TestStatistics<Int64Type>::SetValues() {
-  for (int i = 0; i < NUM_VALUES; i++) {
-    values_[i] = i - 5;  // {-5, -4, -3, -2, -1, 0, 1, 2, 3, 4};
-  }
-
-  // Write UINT64 min/max values
-  stats_[0]
-      .set_min(std::string(reinterpret_cast<const char*>(&values_[5]), sizeof(T)))
-      .set_max(std::string(reinterpret_cast<const char*>(&values_[4]), sizeof(T)));
-
-  // Write INT64 min/max values
-  stats_[1]
-      .set_min(std::string(reinterpret_cast<const char*>(&values_[0]), sizeof(T)))
-      .set_max(std::string(reinterpret_cast<const char*>(&values_[9]), sizeof(T)));
-}
-
-// TYPE::FLOAT
-template <>
-void TestStatistics<FloatType>::SetValues() {
-  for (int i = 0; i < NUM_VALUES; i++) {
-    values_[i] = static_cast<float>(i) -
-                 5;  // {-5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0};
-  }
-
-  // Write Float min/max values
-  stats_[0]
-      .set_min(std::string(reinterpret_cast<const char*>(&values_[0]), sizeof(T)))
-      .set_max(std::string(reinterpret_cast<const char*>(&values_[9]), sizeof(T)));
-}
-
-// TYPE::DOUBLE
-template <>
-void TestStatistics<DoubleType>::SetValues() {
-  for (int i = 0; i < NUM_VALUES; i++) {
-    values_[i] = static_cast<float>(i) -
-                 5;  // {-5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0};
-  }
-
-  // Write Double min/max values
-  stats_[0]
-      .set_min(std::string(reinterpret_cast<const char*>(&values_[0]), sizeof(T)))
-      .set_max(std::string(reinterpret_cast<const char*>(&values_[9]), sizeof(T)));
-}
-
-// TYPE::ByteArray
-template <>
-void TestStatistics<ByteArrayType>::AddNodes(std::string name) {
-  // UTF8 logical type to set Unsigned Statistics
-  fields_.push_back(schema::PrimitiveNode::Make(name, Repetition::REQUIRED,
-                                                Type::BYTE_ARRAY, LogicalType::UTF8));
-}
-
-template <>
-void TestStatistics<ByteArrayType>::SetValues() {
-  int max_byte_array_len = 10;
-  size_t nbytes = NUM_VALUES * max_byte_array_len;
-  values_buf_.resize(nbytes);
-  std::vector<std::string> vals = {u8"c123", u8"b123", u8"a123", u8"d123", u8"e123",
-                                   u8"f123", u8"g123", u8"h123", u8"i123", u8"ü123"};
-
-  uint8_t* base = &values_buf_.data()[0];
-  for (int i = 0; i < NUM_VALUES; i++) {
-    memcpy(base, vals[i].c_str(), vals[i].length());
-    values_[i].ptr = base;
-    values_[i].len = static_cast<uint32_t>(vals[i].length());
-    base += vals[i].length();
-  }
-
-  // Write String min/max values
-  stats_[0]
-      .set_min(
-          std::string(reinterpret_cast<const char*>(vals[2].c_str()), vals[2].length()))
-      .set_max(
-          std::string(reinterpret_cast<const char*>(vals[9].c_str()), vals[9].length()));
-}
-
-// TYPE::FLBAArray
-template <>
-void TestStatistics<FLBAType>::AddNodes(std::string name) {
-  // FLBA has only Unsigned Statistics
-  fields_.push_back(schema::PrimitiveNode::Make(name, Repetition::REQUIRED,
-                                                Type::FIXED_LEN_BYTE_ARRAY,
-                                                LogicalType::NONE, FLBA_LENGTH));
-}
-
-template <>
-void TestStatistics<FLBAType>::SetValues() {
-  size_t nbytes = NUM_VALUES * FLBA_LENGTH;
-  values_buf_.resize(nbytes);
-  char vals[NUM_VALUES][FLBA_LENGTH] = {"b12345", "a12345", "c12345", "d12345", "e12345",
-                                        "f12345", "g12345", "h12345", "z12345", "a12345"};
-
-  uint8_t* base = &values_buf_.data()[0];
-  for (int i = 0; i < NUM_VALUES; i++) {
-    memcpy(base, &vals[i][0], FLBA_LENGTH);
-    values_[i].ptr = base;
-    base += FLBA_LENGTH;
-  }
-
-  // Write FLBA min,max values
-  stats_[0]
-      .set_min(std::string(reinterpret_cast<const char*>(&vals[1][0]), FLBA_LENGTH))
-      .set_max(std::string(reinterpret_cast<const char*>(&vals[8][0]), FLBA_LENGTH));
-}
-
-TYPED_TEST_CASE(TestStatistics, CompareTestTypes);
-
-TYPED_TEST(TestStatistics, MinMax) {
-  this->AddNodes("Column ");
-  this->SetUpSchema();
-  this->WriteParquet();
-  ASSERT_NO_FATAL_FAILURE(this->VerifyParquetStats());
-}
-
-// Ensure UNKNOWN sort order is handled properly
-using TestStatisticsFLBA = TestStatistics<FLBAType>;
-
-TEST_F(TestStatisticsFLBA, UnknownSortOrder) {
-  this->fields_.push_back(schema::PrimitiveNode::Make(
-      "Column 0", Repetition::REQUIRED, Type::FIXED_LEN_BYTE_ARRAY, LogicalType::INTERVAL,
-      FLBA_LENGTH));
-  this->SetUpSchema();
-  this->WriteParquet();
-
-  auto pbuffer = parquet_sink_->GetBuffer();
-  // Create a ParquetReader instance
-  std::unique_ptr<parquet::ParquetFileReader> parquet_reader =
-      parquet::ParquetFileReader::Open(
-          std::make_shared<arrow::io::BufferReader>(pbuffer));
-  // Get the File MetaData
-  std::shared_ptr<parquet::FileMetaData> file_metadata = parquet_reader->metadata();
-  std::shared_ptr<parquet::RowGroupMetaData> rg_metadata = file_metadata->RowGroup(0);
-  std::shared_ptr<parquet::ColumnChunkMetaData> cc_metadata = rg_metadata->ColumnChunk(0);
-
-  // stats should not be set for UNKNOWN sort order
-  ASSERT_FALSE(cc_metadata->is_stats_set());
-}
-
-// PARQUET-1225: Float NaN values may lead to incorrect filtering under certain
-// circumstances
-TEST(TestStatisticsFloatNaN, NaNValues) {
-  constexpr int NUM_VALUES = 10;
-  NodePtr node = PrimitiveNode::Make("nan_float", Repetition::OPTIONAL, Type::FLOAT);
-  ColumnDescriptor descr(node, 1, 1);
-  float values[NUM_VALUES] = {std::nanf(""), -4.0f, -3.0f, -2.0f, -1.0f,
-                              std::nanf(""), 1.0f,  2.0f,  3.0f,  std::nanf("")};
-  float nan_values[NUM_VALUES];
-  for (int i = 0; i < NUM_VALUES; i++) {
-    nan_values[i] = std::nanf("");
-  }
-
-  // Test values
-  TypedRowGroupStatistics<FloatType> nan_stats(&descr);
-  nan_stats.Update(&values[0], NUM_VALUES, 0);
-  float min = nan_stats.min();
-  float max = nan_stats.max();
-  ASSERT_EQ(min, -4.0f);
-  ASSERT_EQ(max, 3.0f);
-
-  // Test all NaNs
-  TypedRowGroupStatistics<FloatType> all_nan_stats(&descr);
-  all_nan_stats.Update(&nan_values[0], NUM_VALUES, 0);
-  min = all_nan_stats.min();
-  max = all_nan_stats.max();
-  ASSERT_TRUE(std::isnan(min));
-  ASSERT_TRUE(std::isnan(max));
-
-  // Test values followed by all NaNs
-  nan_stats.Update(&nan_values[0], NUM_VALUES, 0);
-  min = nan_stats.min();
-  max = nan_stats.max();
-  ASSERT_EQ(min, -4.0f);
-  ASSERT_EQ(max, 3.0f);
-
-  // Test all NaNs followed by values
-  all_nan_stats.Update(&values[0], NUM_VALUES, 0);
-  min = all_nan_stats.min();
-  max = all_nan_stats.max();
-  ASSERT_EQ(min, -4.0f);
-  ASSERT_EQ(max, 3.0f);
-
-  // Test values followed by all NaNs followed by values
-  nan_stats.Update(&values[0], NUM_VALUES, 0);
-  min = nan_stats.min();
-  max = nan_stats.max();
-  ASSERT_EQ(min, -4.0f);
-  ASSERT_EQ(max, 3.0f);
-}
-
-// PARQUET-1225: Float NaN values may lead to incorrect filtering under certain
-// circumstances
-TEST(TestStatisticsFloatNaN, NaNValuesSpaced) {
-  constexpr int NUM_VALUES = 10;
-  NodePtr node = PrimitiveNode::Make("nan_float", Repetition::OPTIONAL, Type::FLOAT);
-  ColumnDescriptor descr(node, 1, 1);
-  float values[NUM_VALUES] = {std::nanf(""), -4.0f, -3.0f, -2.0f, -1.0f,
-                              std::nanf(""), 1.0f,  2.0f,  3.0f,  std::nanf("")};
-  float nan_values[NUM_VALUES];
-  for (int i = 0; i < NUM_VALUES; i++) {
-    nan_values[i] = std::nanf("");
-  }
-  std::vector<uint8_t> valid_bits(BitUtil::BytesForBits(NUM_VALUES) + 1, 255);
-
-  // Test values
-  TypedRowGroupStatistics<FloatType> nan_stats(&descr);
-  nan_stats.UpdateSpaced(&values[0], valid_bits.data(), 0, NUM_VALUES, 0);
-  float min = nan_stats.min();
-  float max = nan_stats.max();
-  ASSERT_EQ(min, -4.0f);
-  ASSERT_EQ(max, 3.0f);
-
-  // Test all NaNs
-  TypedRowGroupStatistics<FloatType> all_nan_stats(&descr);
-  all_nan_stats.UpdateSpaced(&nan_values[0], valid_bits.data(), 0, NUM_VALUES, 0);
-  min = all_nan_stats.min();
-  max = all_nan_stats.max();
-  ASSERT_TRUE(std::isnan(min));
-  ASSERT_TRUE(std::isnan(max));
-
-  // Test values followed by all NaNs
-  nan_stats.UpdateSpaced(&nan_values[0], valid_bits.data(), 0, NUM_VALUES, 0);
-  min = nan_stats.min();
-  max = nan_stats.max();
-  ASSERT_EQ(min, -4.0f);
-  ASSERT_EQ(max, 3.0f);
-
-  // Test all NaNs followed by values
-  all_nan_stats.UpdateSpaced(&values[0], valid_bits.data(), 0, NUM_VALUES, 0);
-  min = all_nan_stats.min();
-  max = all_nan_stats.max();
-  ASSERT_EQ(min, -4.0f);
-  ASSERT_EQ(max, 3.0f);
-
-  // Test values followed by all NaNs followed by values
-  nan_stats.UpdateSpaced(&values[0], valid_bits.data(), 0, NUM_VALUES, 0);
-  min = nan_stats.min();
-  max = nan_stats.max();
-  ASSERT_EQ(min, -4.0f);
-  ASSERT_EQ(max, 3.0f);
-}
-
-// NaN double values may lead to incorrect filtering under certain circumstances
-TEST(TestStatisticsDoubleNaN, NaNValues) {
-  constexpr int NUM_VALUES = 10;
-  NodePtr node = PrimitiveNode::Make("nan_double", Repetition::OPTIONAL, Type::DOUBLE);
-  ColumnDescriptor descr(node, 1, 1);
-  TypedRowGroupStatistics<DoubleType> nan_stats(&descr);
-  double values[NUM_VALUES] = {std::nan(""), std::nan(""), -3.0, -2.0, -1.0,
-                               0.0,          1.0,          2.0,  3.0,  4.0};
-  double* values_ptr = &values[0];
-  nan_stats.Update(values_ptr, NUM_VALUES, 0);
-  double min = nan_stats.min();
-  double max = nan_stats.max();
-
-  ASSERT_EQ(min, -3.0);
-  ASSERT_EQ(max, 4.0);
-}
-}  // namespace test
-}  // namespace parquet
diff --git a/src/parquet/statistics.cc b/src/parquet/statistics.cc
deleted file mode 100644
index ea7f783..0000000
--- a/src/parquet/statistics.cc
+++ /dev/null
@@ -1,334 +0,0 @@
-// 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.
-
-#include <algorithm>
-#include <cstring>
-#include <type_traits>
-
-#include "parquet/encoding-internal.h"
-#include "parquet/exception.h"
-#include "parquet/statistics.h"
-#include "parquet/util/memory.h"
-
-using arrow::default_memory_pool;
-using arrow::MemoryPool;
-
-namespace parquet {
-
-template <typename DType>
-TypedRowGroupStatistics<DType>::TypedRowGroupStatistics(const ColumnDescriptor* schema,
-                                                        MemoryPool* pool)
-    : pool_(pool),
-      min_buffer_(AllocateBuffer(pool_, 0)),
-      max_buffer_(AllocateBuffer(pool_, 0)) {
-  SetDescr(schema);
-  Reset();
-}
-
-template <typename DType>
-TypedRowGroupStatistics<DType>::TypedRowGroupStatistics(const typename DType::c_type& min,
-                                                        const typename DType::c_type& max,
-                                                        int64_t num_values,
-                                                        int64_t null_count,
-                                                        int64_t distinct_count)
-    : pool_(default_memory_pool()),
-      min_buffer_(AllocateBuffer(pool_, 0)),
-      max_buffer_(AllocateBuffer(pool_, 0)) {
-  IncrementNumValues(num_values);
-  IncrementNullCount(null_count);
-  IncrementDistinctCount(distinct_count);
-
-  Copy(min, &min_, min_buffer_.get());
-  Copy(max, &max_, max_buffer_.get());
-  has_min_max_ = true;
-}
-
-template <typename DType>
-TypedRowGroupStatistics<DType>::TypedRowGroupStatistics(
-    const ColumnDescriptor* schema, const std::string& encoded_min,
-    const std::string& encoded_max, int64_t num_values, int64_t null_count,
-    int64_t distinct_count, bool has_min_max, MemoryPool* pool)
-    : pool_(pool),
-      min_buffer_(AllocateBuffer(pool_, 0)),
-      max_buffer_(AllocateBuffer(pool_, 0)) {
-  IncrementNumValues(num_values);
-  IncrementNullCount(null_count);
-  IncrementDistinctCount(distinct_count);
-
-  SetDescr(schema);
-
-  if (!encoded_min.empty()) {
-    PlainDecode(encoded_min, &min_);
-  }
-  if (!encoded_max.empty()) {
-    PlainDecode(encoded_max, &max_);
-  }
-  has_min_max_ = has_min_max;
-}
-
-template <typename DType>
-bool TypedRowGroupStatistics<DType>::HasMinMax() const {
-  return has_min_max_;
-}
-
-template <typename DType>
-void TypedRowGroupStatistics<DType>::SetComparator() {
-  comparator_ =
-      std::static_pointer_cast<CompareDefault<DType> >(Comparator::Make(descr_));
-}
-
-template <typename DType>
-void TypedRowGroupStatistics<DType>::Reset() {
-  ResetCounts();
-  has_min_max_ = false;
-}
-
-template <typename DType>
-inline void TypedRowGroupStatistics<DType>::SetMinMax(const T& min, const T& max) {
-  if (!has_min_max_) {
-    has_min_max_ = true;
-    Copy(min, &min_, min_buffer_.get());
-    Copy(max, &max_, max_buffer_.get());
-  } else {
-    Copy(std::min(min_, min, std::ref(*(this->comparator_))), &min_, min_buffer_.get());
-    Copy(std::max(max_, max, std::ref(*(this->comparator_))), &max_, max_buffer_.get());
-  }
-}
-
-template <typename T, typename Enable = void>
-struct StatsHelper {
-  inline int64_t GetValueBeginOffset(const T* values, int64_t count) { return 0; }
-
-  inline int64_t GetValueEndOffset(const T* values, int64_t count) { return count; }
-
-  inline bool IsNaN(const T value) { return false; }
-};
-
-template <typename T>
-struct StatsHelper<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
-  inline int64_t GetValueBeginOffset(const T* values, int64_t count) {
-    // Skip NaNs
-    for (int64_t i = 0; i < count; i++) {
-      if (!std::isnan(values[i])) {
-        return i;
-      }
-    }
-    return count;
-  }
-
-  inline int64_t GetValueEndOffset(const T* values, int64_t count) {
-    // Skip NaNs
-    for (int64_t i = (count - 1); i >= 0; i--) {
-      if (!std::isnan(values[i])) {
-        return (i + 1);
-      }
-    }
-    return 0;
-  }
-
-  inline bool IsNaN(const T value) { return std::isnan(value); }
-};
-
-template <typename T>
-void SetNaN(T* value) {
-  // no-op
-}
-
-template <>
-void SetNaN<float>(float* value) {
-  *value = std::nanf("");
-}
-
-template <>
-void SetNaN<double>(double* value) {
-  *value = std::nan("");
-}
-
-template <typename DType>
-void TypedRowGroupStatistics<DType>::Update(const T* values, int64_t num_not_null,
-                                            int64_t num_null) {
-  DCHECK(num_not_null >= 0);
-  DCHECK(num_null >= 0);
-
-  IncrementNullCount(num_null);
-  IncrementNumValues(num_not_null);
-  // TODO: support distinct count?
-  if (num_not_null == 0) return;
-
-  // PARQUET-1225: Handle NaNs
-  // The problem arises only if the starting/ending value(s)
-  // of the values-buffer contain NaN
-  StatsHelper<T> helper;
-  int64_t begin_offset = helper.GetValueBeginOffset(values, num_not_null);
-  int64_t end_offset = helper.GetValueEndOffset(values, num_not_null);
-
-  // All values are NaN
-  if (end_offset < begin_offset) {
-    // Set min/max to NaNs in this case.
-    // Don't set has_min_max flag since
-    // these values must be over-written by valid stats later
-    if (!has_min_max_) {
-      SetNaN(&min_);
-      SetNaN(&max_);
-    }
-    return;
-  }
-
-  auto batch_minmax = std::minmax_element(values + begin_offset, values + end_offset,
-                                          std::ref(*(this->comparator_)));
-
-  SetMinMax(*batch_minmax.first, *batch_minmax.second);
-}
-
-template <typename DType>
-void TypedRowGroupStatistics<DType>::UpdateSpaced(const T* values,
-                                                  const uint8_t* valid_bits,
-                                                  int64_t valid_bits_offset,
-                                                  int64_t num_not_null,
-                                                  int64_t num_null) {
-  DCHECK(num_not_null >= 0);
-  DCHECK(num_null >= 0);
-
-  IncrementNullCount(num_null);
-  IncrementNumValues(num_not_null);
-  // TODO: support distinct count?
-  if (num_not_null == 0) return;
-
-  // Find first valid entry and use that for min/max
-  // As (num_not_null != 0) there must be one
-  int64_t length = num_null + num_not_null;
-  int64_t i = 0;
-  ::arrow::internal::BitmapReader valid_bits_reader(valid_bits, valid_bits_offset,
-                                                    length);
-  StatsHelper<T> helper;
-  for (; i < length; i++) {
-    // PARQUET-1225: Handle NaNs
-    if (valid_bits_reader.IsSet() && !helper.IsNaN(values[i])) {
-      break;
-    }
-    valid_bits_reader.Next();
-  }
-
-  // All are NaNs and stats are not set yet
-  if ((i == length) && helper.IsNaN(values[i - 1])) {
-    // Don't set has_min_max flag since
-    // these values must be over-written by valid stats later
-    if (!has_min_max_) {
-      SetNaN(&min_);
-      SetNaN(&max_);
-    }
-    return;
-  }
-
-  T min = values[i];
-  T max = values[i];
-  for (; i < length; i++) {
-    if (valid_bits_reader.IsSet()) {
-      if ((std::ref(*(this->comparator_)))(values[i], min)) {
-        min = values[i];
-      } else if ((std::ref(*(this->comparator_)))(max, values[i])) {
-        max = values[i];
-      }
-    }
-    valid_bits_reader.Next();
-  }
-
-  SetMinMax(min, max);
-}
-
-template <typename DType>
-const typename DType::c_type& TypedRowGroupStatistics<DType>::min() const {
-  return min_;
-}
-
-template <typename DType>
-const typename DType::c_type& TypedRowGroupStatistics<DType>::max() const {
-  return max_;
-}
-
-template <typename DType>
-void TypedRowGroupStatistics<DType>::Merge(const TypedRowGroupStatistics<DType>& other) {
-  this->MergeCounts(other);
-
-  if (!other.HasMinMax()) return;
-
-  SetMinMax(other.min_, other.max_);
-}
-
-template <typename DType>
-std::string TypedRowGroupStatistics<DType>::EncodeMin() {
-  std::string s;
-  if (HasMinMax()) this->PlainEncode(min_, &s);
-  return s;
-}
-
-template <typename DType>
-std::string TypedRowGroupStatistics<DType>::EncodeMax() {
-  std::string s;
-  if (HasMinMax()) this->PlainEncode(max_, &s);
-  return s;
-}
-
-template <typename DType>
-EncodedStatistics TypedRowGroupStatistics<DType>::Encode() {
-  EncodedStatistics s;
-  if (HasMinMax()) {
-    s.set_min(this->EncodeMin());
-    s.set_max(this->EncodeMax());
-  }
-  s.set_null_count(this->null_count());
-  return s;
-}
-
-template <typename DType>
-void TypedRowGroupStatistics<DType>::PlainEncode(const T& src, std::string* dst) {
-  PlainEncoder<DType> encoder(descr(), pool_);
-  encoder.Put(&src, 1);
-  auto buffer = encoder.FlushValues();
-  auto ptr = reinterpret_cast<const char*>(buffer->data());
-  dst->assign(ptr, buffer->size());
-}
-
-template <typename DType>
-void TypedRowGroupStatistics<DType>::PlainDecode(const std::string& src, T* dst) {
-  PlainDecoder<DType> decoder(descr());
-  decoder.SetData(1, reinterpret_cast<const uint8_t*>(src.c_str()),
-                  static_cast<int>(src.size()));
-  decoder.Decode(dst, 1);
-}
-
-template <>
-void TypedRowGroupStatistics<ByteArrayType>::PlainEncode(const T& src, std::string* dst) {
-  dst->assign(reinterpret_cast<const char*>(src.ptr), src.len);
-}
-
-template <>
-void TypedRowGroupStatistics<ByteArrayType>::PlainDecode(const std::string& src, T* dst) {
-  dst->len = static_cast<uint32_t>(src.size());
-  dst->ptr = reinterpret_cast<const uint8_t*>(src.c_str());
-}
-
-template class PARQUET_TEMPLATE_EXPORT TypedRowGroupStatistics<BooleanType>;
-template class PARQUET_TEMPLATE_EXPORT TypedRowGroupStatistics<Int32Type>;
-template class PARQUET_TEMPLATE_EXPORT TypedRowGroupStatistics<Int64Type>;
-template class PARQUET_TEMPLATE_EXPORT TypedRowGroupStatistics<Int96Type>;
-template class PARQUET_TEMPLATE_EXPORT TypedRowGroupStatistics<FloatType>;
-template class PARQUET_TEMPLATE_EXPORT TypedRowGroupStatistics<DoubleType>;
-template class PARQUET_TEMPLATE_EXPORT TypedRowGroupStatistics<ByteArrayType>;
-template class PARQUET_TEMPLATE_EXPORT TypedRowGroupStatistics<FLBAType>;
-
-}  // namespace parquet
diff --git a/src/parquet/statistics.h b/src/parquet/statistics.h
deleted file mode 100644
index d1c4d16..0000000
--- a/src/parquet/statistics.h
+++ /dev/null
@@ -1,249 +0,0 @@
-// 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.
-
-#ifndef PARQUET_COLUMN_STATISTICS_H
-#define PARQUET_COLUMN_STATISTICS_H
-
-#include <algorithm>
-#include <cstdint>
-#include <memory>
-#include <string>
-
-#include "parquet/schema.h"
-#include "parquet/types.h"
-#include "parquet/util/comparison.h"
-#include "parquet/util/memory.h"
-#include "parquet/util/visibility.h"
-
-namespace parquet {
-
-class PARQUET_EXPORT EncodedStatistics {
-  std::shared_ptr<std::string> max_, min_;
-
- public:
-  EncodedStatistics()
-      : max_(std::make_shared<std::string>()), min_(std::make_shared<std::string>()) {}
-
-  const std::string& max() const { return *max_; }
-  const std::string& min() const { return *min_; }
-
-  int64_t null_count = 0;
-  int64_t distinct_count = 0;
-
-  bool has_min = false;
-  bool has_max = false;
-  bool has_null_count = false;
-  bool has_distinct_count = false;
-
-  inline bool is_set() const {
-    return has_min || has_max || has_null_count || has_distinct_count;
-  }
-
-  // larger of the max_ and min_ stat values
-  inline size_t max_stat_length() { return std::max(max_->length(), min_->length()); }
-
-  inline EncodedStatistics& set_max(const std::string& value) {
-    *max_ = value;
-    has_max = true;
-    return *this;
-  }
-
-  inline EncodedStatistics& set_min(const std::string& value) {
-    *min_ = value;
-    has_min = true;
-    return *this;
-  }
-
-  inline EncodedStatistics& set_null_count(int64_t value) {
-    null_count = value;
-    has_null_count = true;
-    return *this;
-  }
-
-  inline EncodedStatistics& set_distinct_count(int64_t value) {
-    distinct_count = value;
-    has_distinct_count = true;
-    return *this;
-  }
-};
-
-template <typename DType>
-class PARQUET_EXPORT TypedRowGroupStatistics;
-
-class PARQUET_EXPORT RowGroupStatistics
-    : public std::enable_shared_from_this<RowGroupStatistics> {
- public:
-  int64_t null_count() const { return statistics_.null_count; }
-  int64_t distinct_count() const { return statistics_.distinct_count; }
-  int64_t num_values() const { return num_values_; }
-
-  virtual bool HasMinMax() const = 0;
-  virtual void Reset() = 0;
-
-  // Plain-encoded minimum value
-  virtual std::string EncodeMin() = 0;
-
-  // Plain-encoded maximum value
-  virtual std::string EncodeMax() = 0;
-
-  virtual EncodedStatistics Encode() = 0;
-
-  // Set the Corresponding Comparator
-  virtual void SetComparator() = 0;
-
-  virtual ~RowGroupStatistics() {}
-
-  Type::type physical_type() const { return descr_->physical_type(); }
-
- protected:
-  const ColumnDescriptor* descr() const { return descr_; }
-  void SetDescr(const ColumnDescriptor* schema) {
-    descr_ = schema;
-    SetComparator();
-  }
-
-  void IncrementNullCount(int64_t n) { statistics_.null_count += n; }
-
-  void IncrementNumValues(int64_t n) { num_values_ += n; }
-
-  void IncrementDistinctCount(int64_t n) { statistics_.distinct_count += n; }
-
-  void MergeCounts(const RowGroupStatistics& other) {
-    this->statistics_.null_count += other.statistics_.null_count;
-    this->statistics_.distinct_count += other.statistics_.distinct_count;
-    this->num_values_ += other.num_values_;
-  }
-
-  void ResetCounts() {
-    this->statistics_.null_count = 0;
-    this->statistics_.distinct_count = 0;
-    this->num_values_ = 0;
-  }
-
-  const ColumnDescriptor* descr_ = nullptr;
-  int64_t num_values_ = 0;
-  EncodedStatistics statistics_;
-};
-
-template <typename DType>
-class TypedRowGroupStatistics : public RowGroupStatistics {
- public:
-  using T = typename DType::c_type;
-
-  TypedRowGroupStatistics(const ColumnDescriptor* schema,
-                          ::arrow::MemoryPool* pool = ::arrow::default_memory_pool());
-
-  TypedRowGroupStatistics(const T& min, const T& max, int64_t num_values,
-                          int64_t null_count, int64_t distinct_count);
-
-  TypedRowGroupStatistics(const ColumnDescriptor* schema, const std::string& encoded_min,
-                          const std::string& encoded_max, int64_t num_values,
-                          int64_t null_count, int64_t distinct_count, bool has_min_max,
-                          ::arrow::MemoryPool* pool = ::arrow::default_memory_pool());
-
-  bool HasMinMax() const override;
-  void Reset() override;
-  void SetComparator() override;
-  void Merge(const TypedRowGroupStatistics<DType>& other);
-
-  void Update(const T* values, int64_t num_not_null, int64_t num_null);
-  void UpdateSpaced(const T* values, const uint8_t* valid_bits, int64_t valid_bits_spaced,
-                    int64_t num_not_null, int64_t num_null);
-  void SetMinMax(const T& min, const T& max);
-
-  const T& min() const;
-  const T& max() const;
-
-  std::string EncodeMin() override;
-  std::string EncodeMax() override;
-  EncodedStatistics Encode() override;
-
- private:
-  bool has_min_max_ = false;
-  T min_;
-  T max_;
-  ::arrow::MemoryPool* pool_;
-  std::shared_ptr<CompareDefault<DType> > comparator_;
-
-  void PlainEncode(const T& src, std::string* dst);
-  void PlainDecode(const std::string& src, T* dst);
-  void Copy(const T& src, T* dst, ResizableBuffer* buffer);
-
-  std::shared_ptr<ResizableBuffer> min_buffer_, max_buffer_;
-};
-
-template <typename DType>
-inline void TypedRowGroupStatistics<DType>::Copy(const T& src, T* dst, ResizableBuffer*) {
-  *dst = src;
-}
-
-template <>
-inline void TypedRowGroupStatistics<FLBAType>::Copy(const FLBA& src, FLBA* dst,
-                                                    ResizableBuffer* buffer) {
-  if (dst->ptr == src.ptr) return;
-  uint32_t len = descr_->type_length();
-  PARQUET_THROW_NOT_OK(buffer->Resize(len, false));
-  std::memcpy(buffer->mutable_data(), src.ptr, len);
-  *dst = FLBA(buffer->data());
-}
-
-template <>
-inline void TypedRowGroupStatistics<ByteArrayType>::Copy(const ByteArray& src,
-                                                         ByteArray* dst,
-                                                         ResizableBuffer* buffer) {
-  if (dst->ptr == src.ptr) return;
-  PARQUET_THROW_NOT_OK(buffer->Resize(src.len, false));
-  std::memcpy(buffer->mutable_data(), src.ptr, src.len);
-  *dst = ByteArray(src.len, buffer->data());
-}
-
-template <>
-void TypedRowGroupStatistics<ByteArrayType>::PlainEncode(const T& src, std::string* dst);
-
-template <>
-void TypedRowGroupStatistics<ByteArrayType>::PlainDecode(const std::string& src, T* dst);
-
-typedef TypedRowGroupStatistics<BooleanType> BoolStatistics;
-typedef TypedRowGroupStatistics<Int32Type> Int32Statistics;
-typedef TypedRowGroupStatistics<Int64Type> Int64Statistics;
-typedef TypedRowGroupStatistics<Int96Type> Int96Statistics;
-typedef TypedRowGroupStatistics<FloatType> FloatStatistics;
-typedef TypedRowGroupStatistics<DoubleType> DoubleStatistics;
-typedef TypedRowGroupStatistics<ByteArrayType> ByteArrayStatistics;
-typedef TypedRowGroupStatistics<FLBAType> FLBAStatistics;
-
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wattributes"
-#endif
-
-PARQUET_EXTERN_TEMPLATE TypedRowGroupStatistics<BooleanType>;
-PARQUET_EXTERN_TEMPLATE TypedRowGroupStatistics<Int32Type>;
-PARQUET_EXTERN_TEMPLATE TypedRowGroupStatistics<Int64Type>;
-PARQUET_EXTERN_TEMPLATE TypedRowGroupStatistics<Int96Type>;
-PARQUET_EXTERN_TEMPLATE TypedRowGroupStatistics<FloatType>;
-PARQUET_EXTERN_TEMPLATE TypedRowGroupStatistics<DoubleType>;
-PARQUET_EXTERN_TEMPLATE TypedRowGroupStatistics<ByteArrayType>;
-PARQUET_EXTERN_TEMPLATE TypedRowGroupStatistics<FLBAType>;
-
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-
-}  // namespace parquet
-
-#endif  // PARQUET_COLUMN_STATISTICS_H
diff --git a/src/parquet/symbols.map b/src/parquet/symbols.map
deleted file mode 100644
index e00751e..0000000
--- a/src/parquet/symbols.map
+++ /dev/null
@@ -1,38 +0,0 @@
-# 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.
-
-{
-  # Symbols marked as 'local' are not exported by the DSO and thus may not
-  # be used by client applications.
-  local:
-    # devtoolset / static-libstdc++ symbols
-    __cxa_*;
-
-    extern "C++" {
-      # boost
-      boost::*;
-
-	  # thrift
-	  apache::thrift::*;
-
-      # devtoolset or -static-libstdc++ - the Red Hat devtoolset statically
-      # links c++11 symbols into binaries so that the result may be executed on
-      # a system with an older libstdc++ which doesn't include the necessary
-      # c++11 symbols.
-      std::*;
-    };
-};
diff --git a/src/parquet/test-specialization.h b/src/parquet/test-specialization.h
deleted file mode 100644
index 3d88cfc..0000000
--- a/src/parquet/test-specialization.h
+++ /dev/null
@@ -1,183 +0,0 @@
-// 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.
-
-// This module defines an abstract interface for iterating through pages in a
-// Parquet column chunk within a row group. It could be extended in the future
-// to iterate through all data pages in all chunks in a file.
-
-#ifndef PARQUET_COLUMN_TEST_SPECIALIZATION_H
-#define PARQUET_COLUMN_TEST_SPECIALIZATION_H
-
-#include <algorithm>
-#include <limits>
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include "parquet/test-util.h"
-
-namespace parquet {
-
-namespace test {
-
-template <>
-void inline InitValues<bool>(int num_values, vector<bool>& values,
-                             vector<uint8_t>& buffer) {
-  values = flip_coins(num_values, 0);
-}
-
-template <>
-void inline InitValues<ByteArray>(int num_values, vector<ByteArray>& values,
-                                  vector<uint8_t>& buffer) {
-  int max_byte_array_len = 12;
-  int num_bytes = static_cast<int>(max_byte_array_len + sizeof(uint32_t));
-  size_t nbytes = num_values * num_bytes;
-  buffer.resize(nbytes);
-  random_byte_array(num_values, 0, buffer.data(), values.data(), max_byte_array_len);
-}
-
-void inline InitWideByteArrayValues(int num_values, vector<ByteArray>& values,
-                                    vector<uint8_t>& buffer, int min_len, int max_len) {
-  int num_bytes = static_cast<int>(max_len + sizeof(uint32_t));
-  size_t nbytes = num_values * num_bytes;
-  buffer.resize(nbytes);
-  random_byte_array(num_values, 0, buffer.data(), values.data(), min_len, max_len);
-}
-
-template <>
-void inline InitValues<FLBA>(int num_values, vector<FLBA>& values,
-                             vector<uint8_t>& buffer) {
-  size_t nbytes = num_values * FLBA_LENGTH;
-  buffer.resize(nbytes);
-  random_fixed_byte_array(num_values, 0, buffer.data(), FLBA_LENGTH, values.data());
-}
-
-template <>
-void inline InitValues<Int96>(int num_values, vector<Int96>& values,
-                              vector<uint8_t>& buffer) {
-  random_Int96_numbers(num_values, 0, std::numeric_limits<int32_t>::min(),
-                       std::numeric_limits<int32_t>::max(), values.data());
-}
-
-inline std::string TestColumnName(int i) {
-  std::stringstream col_name;
-  col_name << "column_" << i;
-  return col_name.str();
-}
-
-// This class lives here because of its dependency on the InitValues specializations.
-template <typename TestType>
-class PrimitiveTypedTest : public ::testing::Test {
- public:
-  typedef typename TestType::c_type T;
-
-  void SetUpSchema(Repetition::type repetition, int num_columns = 1) {
-    std::vector<schema::NodePtr> fields;
-
-    for (int i = 0; i < num_columns; ++i) {
-      std::string name = TestColumnName(i);
-      fields.push_back(schema::PrimitiveNode::Make(name, repetition, TestType::type_num,
-                                                   LogicalType::NONE, FLBA_LENGTH));
-    }
-    node_ = schema::GroupNode::Make("schema", Repetition::REQUIRED, fields);
-    schema_.Init(node_);
-  }
-
-  void GenerateData(int64_t num_values);
-  void SetupValuesOut(int64_t num_values);
-  void SyncValuesOut();
-
- protected:
-  schema::NodePtr node_;
-  SchemaDescriptor schema_;
-
-  // Input buffers
-  std::vector<T> values_;
-
-  std::vector<int16_t> def_levels_;
-
-  std::vector<uint8_t> buffer_;
-  // Pointer to the values, needed as we cannot use vector<bool>::data()
-  T* values_ptr_;
-  std::vector<uint8_t> bool_buffer_;
-
-  // Output buffers
-  std::vector<T> values_out_;
-  std::vector<uint8_t> bool_buffer_out_;
-  T* values_out_ptr_;
-};
-
-template <typename TestType>
-void PrimitiveTypedTest<TestType>::SyncValuesOut() {}
-
-template <>
-void PrimitiveTypedTest<BooleanType>::SyncValuesOut() {
-  std::vector<uint8_t>::const_iterator source_iterator = bool_buffer_out_.begin();
-  std::vector<T>::iterator destination_iterator = values_out_.begin();
-  while (source_iterator != bool_buffer_out_.end()) {
-    *destination_iterator++ = *source_iterator++ != 0;
-  }
-}
-
-template <typename TestType>
-void PrimitiveTypedTest<TestType>::SetupValuesOut(int64_t num_values) {
-  values_out_.clear();
-  values_out_.resize(num_values);
-  values_out_ptr_ = values_out_.data();
-}
-
-template <>
-void PrimitiveTypedTest<BooleanType>::SetupValuesOut(int64_t num_values) {
-  values_out_.clear();
-  values_out_.resize(num_values);
-
-  bool_buffer_out_.clear();
-  bool_buffer_out_.resize(num_values);
-  // Write once to all values so we can copy it without getting Valgrind errors
-  // about uninitialised values.
-  std::fill(bool_buffer_out_.begin(), bool_buffer_out_.end(), true);
-  values_out_ptr_ = reinterpret_cast<bool*>(bool_buffer_out_.data());
-}
-
-template <typename TestType>
-void PrimitiveTypedTest<TestType>::GenerateData(int64_t num_values) {
-  def_levels_.resize(num_values);
-  values_.resize(num_values);
-
-  InitValues<T>(static_cast<int>(num_values), values_, buffer_);
-  values_ptr_ = values_.data();
-
-  std::fill(def_levels_.begin(), def_levels_.end(), 1);
-}
-
-template <>
-void PrimitiveTypedTest<BooleanType>::GenerateData(int64_t num_values) {
-  def_levels_.resize(num_values);
-  values_.resize(num_values);
-
-  InitValues<T>(static_cast<int>(num_values), values_, buffer_);
-  bool_buffer_.resize(num_values);
-  std::copy(values_.begin(), values_.end(), bool_buffer_.begin());
-  values_ptr_ = reinterpret_cast<bool*>(bool_buffer_.data());
-
-  std::fill(def_levels_.begin(), def_levels_.end(), 1);
-}
-}  // namespace test
-
-}  // namespace parquet
-
-#endif  // PARQUET_COLUMN_TEST_SPECIALIZATION_H
diff --git a/src/parquet/test-util.h b/src/parquet/test-util.h
deleted file mode 100644
index 3e74398..0000000
--- a/src/parquet/test-util.h
+++ /dev/null
@@ -1,447 +0,0 @@
-// 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.
-
-// This module defines an abstract interface for iterating through pages in a
-// Parquet column chunk within a row group. It could be extended in the future
-// to iterate through all data pages in all chunks in a file.
-
-#ifndef PARQUET_COLUMN_TEST_UTIL_H
-#define PARQUET_COLUMN_TEST_UTIL_H
-
-#include <algorithm>
-#include <limits>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include "parquet/column_page.h"
-#include "parquet/column_reader.h"
-#include "parquet/column_writer.h"
-#include "parquet/encoding-internal.h"
-#include "parquet/util/memory.h"
-#include "parquet/util/test-common.h"
-
-using std::shared_ptr;
-using std::vector;
-
-namespace parquet {
-
-static constexpr int FLBA_LENGTH = 12;
-
-bool operator==(const FixedLenByteArray& a, const FixedLenByteArray& b) {
-  return 0 == memcmp(a.ptr, b.ptr, FLBA_LENGTH);
-}
-
-namespace test {
-
-template <typename T>
-static void InitValues(int num_values, vector<T>& values, vector<uint8_t>& buffer) {
-  random_numbers(num_values, 0, std::numeric_limits<T>::min(),
-                 std::numeric_limits<T>::max(), values.data());
-}
-
-template <typename T>
-static void InitDictValues(int num_values, int num_dicts, vector<T>& values,
-                           vector<uint8_t>& buffer) {
-  int repeat_factor = num_values / num_dicts;
-  InitValues<T>(num_dicts, values, buffer);
-  // add some repeated values
-  for (int j = 1; j < repeat_factor; ++j) {
-    for (int i = 0; i < num_dicts; ++i) {
-      std::memcpy(&values[num_dicts * j + i], &values[i], sizeof(T));
-    }
-  }
-  // computed only dict_per_page * repeat_factor - 1 values < num_values
-  // compute remaining
-  for (int i = num_dicts * repeat_factor; i < num_values; ++i) {
-    std::memcpy(&values[i], &values[i - num_dicts * repeat_factor], sizeof(T));
-  }
-}
-
-class MockPageReader : public PageReader {
- public:
-  explicit MockPageReader(const vector<shared_ptr<Page>>& pages)
-      : pages_(pages), page_index_(0) {}
-
-  shared_ptr<Page> NextPage() override {
-    if (page_index_ == static_cast<int>(pages_.size())) {
-      // EOS to consumer
-      return shared_ptr<Page>(nullptr);
-    }
-    return pages_[page_index_++];
-  }
-
-  // No-op
-  void set_max_page_header_size(uint32_t size) override {}
-
- private:
-  vector<shared_ptr<Page>> pages_;
-  int page_index_;
-};
-
-// TODO(wesm): this is only used for testing for now. Refactor to form part of
-// primary file write path
-template <typename Type>
-class DataPageBuilder {
- public:
-  typedef typename Type::c_type T;
-
-  // This class writes data and metadata to the passed inputs
-  explicit DataPageBuilder(InMemoryOutputStream* sink)
-      : sink_(sink),
-        num_values_(0),
-        encoding_(Encoding::PLAIN),
-        definition_level_encoding_(Encoding::RLE),
-        repetition_level_encoding_(Encoding::RLE),
-        have_def_levels_(false),
-        have_rep_levels_(false),
-        have_values_(false) {}
-
-  void AppendDefLevels(const vector<int16_t>& levels, int16_t max_level,
-                       Encoding::type encoding = Encoding::RLE) {
-    AppendLevels(levels, max_level, encoding);
-
-    num_values_ = std::max(static_cast<int32_t>(levels.size()), num_values_);
-    definition_level_encoding_ = encoding;
-    have_def_levels_ = true;
-  }
-
-  void AppendRepLevels(const vector<int16_t>& levels, int16_t max_level,
-                       Encoding::type encoding = Encoding::RLE) {
-    AppendLevels(levels, max_level, encoding);
-
-    num_values_ = std::max(static_cast<int32_t>(levels.size()), num_values_);
-    repetition_level_encoding_ = encoding;
-    have_rep_levels_ = true;
-  }
-
-  void AppendValues(const ColumnDescriptor* d, const vector<T>& values,
-                    Encoding::type encoding = Encoding::PLAIN) {
-    PlainEncoder<Type> encoder(d);
-    encoder.Put(&values[0], static_cast<int>(values.size()));
-    std::shared_ptr<Buffer> values_sink = encoder.FlushValues();
-    sink_->Write(values_sink->data(), values_sink->size());
-
-    num_values_ = std::max(static_cast<int32_t>(values.size()), num_values_);
-    encoding_ = encoding;
-    have_values_ = true;
-  }
-
-  int32_t num_values() const { return num_values_; }
-
-  Encoding::type encoding() const { return encoding_; }
-
-  Encoding::type rep_level_encoding() const { return repetition_level_encoding_; }
-
-  Encoding::type def_level_encoding() const { return definition_level_encoding_; }
-
- private:
-  InMemoryOutputStream* sink_;
-
-  int32_t num_values_;
-  Encoding::type encoding_;
-  Encoding::type definition_level_encoding_;
-  Encoding::type repetition_level_encoding_;
-
-  bool have_def_levels_;
-  bool have_rep_levels_;
-  bool have_values_;
-
-  // Used internally for both repetition and definition levels
-  void AppendLevels(const vector<int16_t>& levels, int16_t max_level,
-                    Encoding::type encoding) {
-    if (encoding != Encoding::RLE) {
-      ParquetException::NYI("only rle encoding currently implemented");
-    }
-
-    // TODO: compute a more precise maximum size for the encoded levels
-    vector<uint8_t> encode_buffer(levels.size() * 2);
-
-    // We encode into separate memory from the output stream because the
-    // RLE-encoded bytes have to be preceded in the stream by their absolute
-    // size.
-    LevelEncoder encoder;
-    encoder.Init(encoding, max_level, static_cast<int>(levels.size()),
-                 encode_buffer.data(), static_cast<int>(encode_buffer.size()));
-
-    encoder.Encode(static_cast<int>(levels.size()), levels.data());
-
-    int32_t rle_bytes = encoder.len();
-    sink_->Write(reinterpret_cast<const uint8_t*>(&rle_bytes), sizeof(int32_t));
-    sink_->Write(encode_buffer.data(), rle_bytes);
-  }
-};
-
-template <>
-void DataPageBuilder<BooleanType>::AppendValues(const ColumnDescriptor* d,
-                                                const vector<bool>& values,
-                                                Encoding::type encoding) {
-  if (encoding != Encoding::PLAIN) {
-    ParquetException::NYI("only plain encoding currently implemented");
-  }
-  PlainEncoder<BooleanType> encoder(d);
-  encoder.Put(values, static_cast<int>(values.size()));
-  std::shared_ptr<Buffer> buffer = encoder.FlushValues();
-  sink_->Write(buffer->data(), buffer->size());
-
-  num_values_ = std::max(static_cast<int32_t>(values.size()), num_values_);
-  encoding_ = encoding;
-  have_values_ = true;
-}
-
-template <typename Type>
-static shared_ptr<DataPage> MakeDataPage(
-    const ColumnDescriptor* d, const vector<typename Type::c_type>& values, int num_vals,
-    Encoding::type encoding, const uint8_t* indices, int indices_size,
-    const vector<int16_t>& def_levels, int16_t max_def_level,
-    const vector<int16_t>& rep_levels, int16_t max_rep_level) {
-  int num_values = 0;
-
-  InMemoryOutputStream page_stream;
-  test::DataPageBuilder<Type> page_builder(&page_stream);
-
-  if (!rep_levels.empty()) {
-    page_builder.AppendRepLevels(rep_levels, max_rep_level);
-  }
-  if (!def_levels.empty()) {
-    page_builder.AppendDefLevels(def_levels, max_def_level);
-  }
-
-  if (encoding == Encoding::PLAIN) {
-    page_builder.AppendValues(d, values, encoding);
-    num_values = page_builder.num_values();
-  } else {  // DICTIONARY PAGES
-    page_stream.Write(indices, indices_size);
-    num_values = std::max(page_builder.num_values(), num_vals);
-  }
-
-  auto buffer = page_stream.GetBuffer();
-
-  return std::make_shared<DataPage>(buffer, num_values, encoding,
-                                    page_builder.def_level_encoding(),
-                                    page_builder.rep_level_encoding());
-}
-
-template <typename TYPE>
-class DictionaryPageBuilder {
- public:
-  typedef typename TYPE::c_type TC;
-  static constexpr int TN = TYPE::type_num;
-
-  // This class writes data and metadata to the passed inputs
-  explicit DictionaryPageBuilder(const ColumnDescriptor* d)
-      : num_dict_values_(0), have_values_(false) {
-    encoder_.reset(new DictEncoder<TYPE>(d, &pool_));
-  }
-
-  ~DictionaryPageBuilder() { pool_.FreeAll(); }
-
-  shared_ptr<Buffer> AppendValues(const vector<TC>& values) {
-    int num_values = static_cast<int>(values.size());
-    // Dictionary encoding
-    encoder_->Put(values.data(), num_values);
-    num_dict_values_ = encoder_->num_entries();
-    have_values_ = true;
-    return encoder_->FlushValues();
-  }
-
-  shared_ptr<Buffer> WriteDict() {
-    std::shared_ptr<ResizableBuffer> dict_buffer =
-        AllocateBuffer(::arrow::default_memory_pool(), encoder_->dict_encoded_size());
-    encoder_->WriteDict(dict_buffer->mutable_data());
-    return dict_buffer;
-  }
-
-  int32_t num_values() const { return num_dict_values_; }
-
- private:
-  ChunkedAllocator pool_;
-  shared_ptr<DictEncoder<TYPE>> encoder_;
-  int32_t num_dict_values_;
-  bool have_values_;
-};
-
-template <>
-DictionaryPageBuilder<BooleanType>::DictionaryPageBuilder(const ColumnDescriptor* d) {
-  ParquetException::NYI("only plain encoding currently implemented for boolean");
-}
-
-template <>
-shared_ptr<Buffer> DictionaryPageBuilder<BooleanType>::WriteDict() {
-  ParquetException::NYI("only plain encoding currently implemented for boolean");
-  return nullptr;
-}
-
-template <>
-shared_ptr<Buffer> DictionaryPageBuilder<BooleanType>::AppendValues(
-    const vector<TC>& values) {
-  ParquetException::NYI("only plain encoding currently implemented for boolean");
-  return nullptr;
-}
-
-template <typename Type>
-static shared_ptr<DictionaryPage> MakeDictPage(
-    const ColumnDescriptor* d, const vector<typename Type::c_type>& values,
-    const vector<int>& values_per_page, Encoding::type encoding,
-    vector<shared_ptr<Buffer>>& rle_indices) {
-  InMemoryOutputStream page_stream;
-  test::DictionaryPageBuilder<Type> page_builder(d);
-  int num_pages = static_cast<int>(values_per_page.size());
-  int value_start = 0;
-
-  for (int i = 0; i < num_pages; i++) {
-    rle_indices.push_back(page_builder.AppendValues(
-        slice(values, value_start, value_start + values_per_page[i])));
-    value_start += values_per_page[i];
-  }
-
-  auto buffer = page_builder.WriteDict();
-
-  return std::make_shared<DictionaryPage>(buffer, page_builder.num_values(),
-                                          Encoding::PLAIN);
-}
-
-// Given def/rep levels and values create multiple dict pages
-template <typename Type>
-static void PaginateDict(const ColumnDescriptor* d,
-                         const vector<typename Type::c_type>& values,
-                         const vector<int16_t>& def_levels, int16_t max_def_level,
-                         const vector<int16_t>& rep_levels, int16_t max_rep_level,
-                         int num_levels_per_page, const vector<int>& values_per_page,
-                         vector<shared_ptr<Page>>& pages,
-                         Encoding::type encoding = Encoding::RLE_DICTIONARY) {
-  int num_pages = static_cast<int>(values_per_page.size());
-  vector<shared_ptr<Buffer>> rle_indices;
-  shared_ptr<DictionaryPage> dict_page =
-      MakeDictPage<Type>(d, values, values_per_page, encoding, rle_indices);
-  pages.push_back(dict_page);
-  int def_level_start = 0;
-  int def_level_end = 0;
-  int rep_level_start = 0;
-  int rep_level_end = 0;
-  for (int i = 0; i < num_pages; i++) {
-    if (max_def_level > 0) {
-      def_level_start = i * num_levels_per_page;
-      def_level_end = (i + 1) * num_levels_per_page;
-    }
-    if (max_rep_level > 0) {
-      rep_level_start = i * num_levels_per_page;
-      rep_level_end = (i + 1) * num_levels_per_page;
-    }
-    shared_ptr<DataPage> data_page = MakeDataPage<Int32Type>(
-        d, {}, values_per_page[i], encoding, rle_indices[i]->data(),
-        static_cast<int>(rle_indices[i]->size()),
-        slice(def_levels, def_level_start, def_level_end), max_def_level,
-        slice(rep_levels, rep_level_start, rep_level_end), max_rep_level);
-    pages.push_back(data_page);
-  }
-}
-
-// Given def/rep levels and values create multiple plain pages
-template <typename Type>
-static void PaginatePlain(const ColumnDescriptor* d,
-                          const vector<typename Type::c_type>& values,
-                          const vector<int16_t>& def_levels, int16_t max_def_level,
-                          const vector<int16_t>& rep_levels, int16_t max_rep_level,
-                          int num_levels_per_page, const vector<int>& values_per_page,
-                          vector<shared_ptr<Page>>& pages,
-                          Encoding::type encoding = Encoding::PLAIN) {
-  int num_pages = static_cast<int>(values_per_page.size());
-  int def_level_start = 0;
-  int def_level_end = 0;
-  int rep_level_start = 0;
-  int rep_level_end = 0;
-  int value_start = 0;
-  for (int i = 0; i < num_pages; i++) {
-    if (max_def_level > 0) {
-      def_level_start = i * num_levels_per_page;
-      def_level_end = (i + 1) * num_levels_per_page;
-    }
-    if (max_rep_level > 0) {
-      rep_level_start = i * num_levels_per_page;
-      rep_level_end = (i + 1) * num_levels_per_page;
-    }
-    shared_ptr<DataPage> page = MakeDataPage<Type>(
-        d, slice(values, value_start, value_start + values_per_page[i]),
-        values_per_page[i], encoding, nullptr, 0,
-        slice(def_levels, def_level_start, def_level_end), max_def_level,
-        slice(rep_levels, rep_level_start, rep_level_end), max_rep_level);
-    pages.push_back(page);
-    value_start += values_per_page[i];
-  }
-}
-
-// Generates pages from randomly generated data
-template <typename Type>
-static int MakePages(const ColumnDescriptor* d, int num_pages, int levels_per_page,
-                     vector<int16_t>& def_levels, vector<int16_t>& rep_levels,
-                     vector<typename Type::c_type>& values, vector<uint8_t>& buffer,
-                     vector<shared_ptr<Page>>& pages,
-                     Encoding::type encoding = Encoding::PLAIN) {
-  int num_levels = levels_per_page * num_pages;
-  int num_values = 0;
-  uint32_t seed = 0;
-  int16_t zero = 0;
-  int16_t max_def_level = d->max_definition_level();
-  int16_t max_rep_level = d->max_repetition_level();
-  vector<int> values_per_page(num_pages, levels_per_page);
-  // Create definition levels
-  if (max_def_level > 0) {
-    def_levels.resize(num_levels);
-    random_numbers(num_levels, seed, zero, max_def_level, def_levels.data());
-    for (int p = 0; p < num_pages; p++) {
-      int num_values_per_page = 0;
-      for (int i = 0; i < levels_per_page; i++) {
-        if (def_levels[i + p * levels_per_page] == max_def_level) {
-          num_values_per_page++;
-          num_values++;
-        }
-      }
-      values_per_page[p] = num_values_per_page;
-    }
-  } else {
-    num_values = num_levels;
-  }
-  // Create repitition levels
-  if (max_rep_level > 0) {
-    rep_levels.resize(num_levels);
-    random_numbers(num_levels, seed, zero, max_rep_level, rep_levels.data());
-  }
-  // Create values
-  values.resize(num_values);
-  if (encoding == Encoding::PLAIN) {
-    InitValues<typename Type::c_type>(num_values, values, buffer);
-    PaginatePlain<Type>(d, values, def_levels, max_def_level, rep_levels, max_rep_level,
-                        levels_per_page, values_per_page, pages);
-  } else if (encoding == Encoding::RLE_DICTIONARY ||
-             encoding == Encoding::PLAIN_DICTIONARY) {
-    // Calls InitValues and repeats the data
-    InitDictValues<typename Type::c_type>(num_values, levels_per_page, values, buffer);
-    PaginateDict<Type>(d, values, def_levels, max_def_level, rep_levels, max_rep_level,
-                       levels_per_page, values_per_page, pages);
-  }
-
-  return num_values;
-}
-
-}  // namespace test
-
-}  // namespace parquet
-
-#endif  // PARQUET_COLUMN_TEST_UTIL_H
diff --git a/src/parquet/thrift.h b/src/parquet/thrift.h
deleted file mode 100644
index ec7ac90..0000000
--- a/src/parquet/thrift.h
+++ /dev/null
@@ -1,159 +0,0 @@
-// 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.
-
-#ifndef PARQUET_THRIFT_UTIL_H
-#define PARQUET_THRIFT_UTIL_H
-
-#include <cstdint>
-// Check if thrift version < 0.11.0
-// or if FORCE_BOOST_SMART_PTR is defined. Ref: https://thrift.apache.org/lib/cpp
-#if defined(PARQUET_THRIFT_USE_BOOST) || defined(FORCE_BOOST_SMART_PTR)
-#include <boost/shared_ptr.hpp>
-#else
-#include <memory>
-#endif
-
-// TCompactProtocol requires some #defines to work right.
-#define SIGNED_RIGHT_SHIFT_IS 1
-#define ARITHMETIC_RIGHT_SHIFT 1
-#include <thrift/TApplicationException.h>
-#include <thrift/protocol/TCompactProtocol.h>
-#include <thrift/protocol/TDebugProtocol.h>
-
-#include <thrift/protocol/TBinaryProtocol.h>
-#include <thrift/transport/TBufferTransports.h>
-#include <sstream>
-
-#include "parquet/exception.h"
-#include "parquet/parquet_types.h"
-#include "parquet/util/logging.h"
-#include "parquet/util/memory.h"
-
-namespace parquet {
-
-// Check if thrift version < 0.11.0
-// or if FORCE_BOOST_SMART_PTR is defined. Ref: https://thrift.apache.org/lib/cpp
-#if defined(PARQUET_THRIFT_USE_BOOST) || defined(FORCE_BOOST_SMART_PTR)
-using ::boost::shared_ptr;
-#else
-using ::std::shared_ptr;
-#endif
-
-// ----------------------------------------------------------------------
-// Convert Thrift enums to / from parquet enums
-
-static inline Type::type FromThrift(format::Type::type type) {
-  return static_cast<Type::type>(type);
-}
-
-static inline LogicalType::type FromThrift(format::ConvertedType::type type) {
-  // item 0 is NONE
-  return static_cast<LogicalType::type>(static_cast<int>(type) + 1);
-}
-
-static inline Repetition::type FromThrift(format::FieldRepetitionType::type type) {
-  return static_cast<Repetition::type>(type);
-}
-
-static inline Encoding::type FromThrift(format::Encoding::type type) {
-  return static_cast<Encoding::type>(type);
-}
-
-static inline Compression::type FromThrift(format::CompressionCodec::type type) {
-  return static_cast<Compression::type>(type);
-}
-
-static inline format::Type::type ToThrift(Type::type type) {
-  return static_cast<format::Type::type>(type);
-}
-
-static inline format::ConvertedType::type ToThrift(LogicalType::type type) {
-  // item 0 is NONE
-  DCHECK_NE(type, LogicalType::NONE);
-  return static_cast<format::ConvertedType::type>(static_cast<int>(type) - 1);
-}
-
-static inline format::FieldRepetitionType::type ToThrift(Repetition::type type) {
-  return static_cast<format::FieldRepetitionType::type>(type);
-}
-
-static inline format::Encoding::type ToThrift(Encoding::type type) {
-  return static_cast<format::Encoding::type>(type);
-}
-
-static inline format::CompressionCodec::type ToThrift(Compression::type type) {
-  return static_cast<format::CompressionCodec::type>(type);
-}
-
-// ----------------------------------------------------------------------
-// Thrift struct serialization / deserialization utilities
-
-// Deserialize a thrift message from buf/len.  buf/len must at least contain
-// all the bytes needed to store the thrift message.  On return, len will be
-// set to the actual length of the header.
-template <class T>
-inline void DeserializeThriftMsg(const uint8_t* buf, uint32_t* len, T* deserialized_msg) {
-  // Deserialize msg bytes into c++ thrift msg using memory transport.
-  shared_ptr<apache::thrift::transport::TMemoryBuffer> tmem_transport(
-      new apache::thrift::transport::TMemoryBuffer(const_cast<uint8_t*>(buf), *len));
-  apache::thrift::protocol::TCompactProtocolFactoryT<
-      apache::thrift::transport::TMemoryBuffer>
-      tproto_factory;
-  shared_ptr<apache::thrift::protocol::TProtocol> tproto =
-      tproto_factory.getProtocol(tmem_transport);
-  try {
-    deserialized_msg->read(tproto.get());
-  } catch (std::exception& e) {
-    std::stringstream ss;
-    ss << "Couldn't deserialize thrift: " << e.what() << "\n";
-    throw ParquetException(ss.str());
-  }
-  uint32_t bytes_left = tmem_transport->available_read();
-  *len = *len - bytes_left;
-}
-
-// Serialize obj into a buffer. The result is returned as a string.
-// The arguments are the object to be serialized and
-// the expected size of the serialized object
-template <class T>
-inline int64_t SerializeThriftMsg(T* obj, uint32_t len, OutputStream* out) {
-  shared_ptr<apache::thrift::transport::TMemoryBuffer> mem_buffer(
-      new apache::thrift::transport::TMemoryBuffer(len));
-  apache::thrift::protocol::TCompactProtocolFactoryT<
-      apache::thrift::transport::TMemoryBuffer>
-      tproto_factory;
-  shared_ptr<apache::thrift::protocol::TProtocol> tproto =
-      tproto_factory.getProtocol(mem_buffer);
-  try {
-    mem_buffer->resetBuffer();
-    obj->write(tproto.get());
-  } catch (std::exception& e) {
-    std::stringstream ss;
-    ss << "Couldn't serialize thrift: " << e.what() << "\n";
-    throw ParquetException(ss.str());
-  }
-
-  uint8_t* out_buffer;
-  uint32_t out_length;
-  mem_buffer->getBuffer(&out_buffer, &out_length);
-  out->Write(out_buffer, out_length);
-  return out_length;
-}
-
-}  // namespace parquet
-
-#endif  // PARQUET_THRIFT_UTIL_H
diff --git a/src/parquet/types-test.cc b/src/parquet/types-test.cc
deleted file mode 100644
index 6b184e3..0000000
--- a/src/parquet/types-test.cc
+++ /dev/null
@@ -1,142 +0,0 @@
-// 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.
-
-#include <gtest/gtest.h>
-
-#include <string>
-
-#include "parquet/types.h"
-
-namespace parquet {
-
-TEST(TestTypeToString, PhysicalTypes) {
-  ASSERT_STREQ("BOOLEAN", TypeToString(Type::BOOLEAN).c_str());
-  ASSERT_STREQ("INT32", TypeToString(Type::INT32).c_str());
-  ASSERT_STREQ("INT64", TypeToString(Type::INT64).c_str());
-  ASSERT_STREQ("INT96", TypeToString(Type::INT96).c_str());
-  ASSERT_STREQ("FLOAT", TypeToString(Type::FLOAT).c_str());
-  ASSERT_STREQ("DOUBLE", TypeToString(Type::DOUBLE).c_str());
-  ASSERT_STREQ("BYTE_ARRAY", TypeToString(Type::BYTE_ARRAY).c_str());
-  ASSERT_STREQ("FIXED_LEN_BYTE_ARRAY", TypeToString(Type::FIXED_LEN_BYTE_ARRAY).c_str());
-}
-
-TEST(TestLogicalTypeToString, LogicalTypes) {
-  ASSERT_STREQ("NONE", LogicalTypeToString(LogicalType::NONE).c_str());
-  ASSERT_STREQ("UTF8", LogicalTypeToString(LogicalType::UTF8).c_str());
-  ASSERT_STREQ("MAP_KEY_VALUE", LogicalTypeToString(LogicalType::MAP_KEY_VALUE).c_str());
-  ASSERT_STREQ("LIST", LogicalTypeToString(LogicalType::LIST).c_str());
-  ASSERT_STREQ("ENUM", LogicalTypeToString(LogicalType::ENUM).c_str());
-  ASSERT_STREQ("DECIMAL", LogicalTypeToString(LogicalType::DECIMAL).c_str());
-  ASSERT_STREQ("DATE", LogicalTypeToString(LogicalType::DATE).c_str());
-  ASSERT_STREQ("TIME_MILLIS", LogicalTypeToString(LogicalType::TIME_MILLIS).c_str());
-  ASSERT_STREQ("TIME_MICROS", LogicalTypeToString(LogicalType::TIME_MICROS).c_str());
-  ASSERT_STREQ("TIMESTAMP_MILLIS",
-               LogicalTypeToString(LogicalType::TIMESTAMP_MILLIS).c_str());
-  ASSERT_STREQ("TIMESTAMP_MICROS",
-               LogicalTypeToString(LogicalType::TIMESTAMP_MICROS).c_str());
-  ASSERT_STREQ("UINT_8", LogicalTypeToString(LogicalType::UINT_8).c_str());
-  ASSERT_STREQ("UINT_16", LogicalTypeToString(LogicalType::UINT_16).c_str());
-  ASSERT_STREQ("UINT_32", LogicalTypeToString(LogicalType::UINT_32).c_str());
-  ASSERT_STREQ("UINT_64", LogicalTypeToString(LogicalType::UINT_64).c_str());
-  ASSERT_STREQ("INT_8", LogicalTypeToString(LogicalType::INT_8).c_str());
-  ASSERT_STREQ("INT_16", LogicalTypeToString(LogicalType::INT_16).c_str());
-  ASSERT_STREQ("INT_32", LogicalTypeToString(LogicalType::INT_32).c_str());
-  ASSERT_STREQ("INT_64", LogicalTypeToString(LogicalType::INT_64).c_str());
-  ASSERT_STREQ("JSON", LogicalTypeToString(LogicalType::JSON).c_str());
-  ASSERT_STREQ("BSON", LogicalTypeToString(LogicalType::BSON).c_str());
-  ASSERT_STREQ("INTERVAL", LogicalTypeToString(LogicalType::INTERVAL).c_str());
-}
-
-TEST(TypePrinter, StatisticsTypes) {
-#if !(defined(_WIN32) || defined(__CYGWIN__))
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-  std::string smin;
-  std::string smax;
-  int32_t int_min = 1024;
-  int32_t int_max = 2048;
-  smin = std::string(reinterpret_cast<char*>(&int_min), sizeof(int32_t));
-  smax = std::string(reinterpret_cast<char*>(&int_max), sizeof(int32_t));
-  ASSERT_STREQ("1024", FormatStatValue(Type::INT32, smin).c_str());
-  ASSERT_STREQ("1024", FormatStatValue(Type::INT32, smin.c_str()).c_str());
-  ASSERT_STREQ("2048", FormatStatValue(Type::INT32, smax).c_str());
-  ASSERT_STREQ("2048", FormatStatValue(Type::INT32, smax.c_str()).c_str());
-
-  int64_t int64_min = 10240000000000;
-  int64_t int64_max = 20480000000000;
-  smin = std::string(reinterpret_cast<char*>(&int64_min), sizeof(int64_t));
-  smax = std::string(reinterpret_cast<char*>(&int64_max), sizeof(int64_t));
-  ASSERT_STREQ("10240000000000", FormatStatValue(Type::INT64, smin).c_str());
-  ASSERT_STREQ("10240000000000", FormatStatValue(Type::INT64, smin.c_str()).c_str());
-  ASSERT_STREQ("20480000000000", FormatStatValue(Type::INT64, smax).c_str());
-  ASSERT_STREQ("20480000000000", FormatStatValue(Type::INT64, smax.c_str()).c_str());
-
-  float float_min = 1.024f;
-  float float_max = 2.048f;
-  smin = std::string(reinterpret_cast<char*>(&float_min), sizeof(float));
-  smax = std::string(reinterpret_cast<char*>(&float_max), sizeof(float));
-  ASSERT_STREQ("1.024", FormatStatValue(Type::FLOAT, smin).c_str());
-  ASSERT_STREQ("1.024", FormatStatValue(Type::FLOAT, smin.c_str()).c_str());
-  ASSERT_STREQ("2.048", FormatStatValue(Type::FLOAT, smax).c_str());
-  ASSERT_STREQ("2.048", FormatStatValue(Type::FLOAT, smax.c_str()).c_str());
-
-  double double_min = 1.0245;
-  double double_max = 2.0489;
-  smin = std::string(reinterpret_cast<char*>(&double_min), sizeof(double));
-  smax = std::string(reinterpret_cast<char*>(&double_max), sizeof(double));
-  ASSERT_STREQ("1.0245", FormatStatValue(Type::DOUBLE, smin).c_str());
-  ASSERT_STREQ("1.0245", FormatStatValue(Type::DOUBLE, smin.c_str()).c_str());
-  ASSERT_STREQ("2.0489", FormatStatValue(Type::DOUBLE, smax).c_str());
-  ASSERT_STREQ("2.0489", FormatStatValue(Type::DOUBLE, smax.c_str()).c_str());
-
-  Int96 Int96_min = {{1024, 2048, 4096}};
-  Int96 Int96_max = {{2048, 4096, 8192}};
-  smin = std::string(reinterpret_cast<char*>(&Int96_min), sizeof(Int96));
-  smax = std::string(reinterpret_cast<char*>(&Int96_max), sizeof(Int96));
-  ASSERT_STREQ("1024 2048 4096", FormatStatValue(Type::INT96, smin).c_str());
-  ASSERT_STREQ("1024 2048 4096", FormatStatValue(Type::INT96, smin.c_str()).c_str());
-  ASSERT_STREQ("2048 4096 8192", FormatStatValue(Type::INT96, smax).c_str());
-  ASSERT_STREQ("2048 4096 8192", FormatStatValue(Type::INT96, smax.c_str()).c_str());
-
-  smin = std::string("abcdef");
-  smax = std::string("ijklmnop");
-  ASSERT_STREQ("abcdef", FormatStatValue(Type::BYTE_ARRAY, smin).c_str());
-  ASSERT_STREQ("abcdef", FormatStatValue(Type::BYTE_ARRAY, smin.c_str()).c_str());
-  ASSERT_STREQ("ijklmnop", FormatStatValue(Type::BYTE_ARRAY, smax).c_str());
-  ASSERT_STREQ("ijklmnop", FormatStatValue(Type::BYTE_ARRAY, smax.c_str()).c_str());
-
-  // PARQUET-1357: FormatStatValue truncates binary statistics on zero character
-  smax.push_back('\0');
-  ASSERT_EQ(smax, FormatStatValue(Type::BYTE_ARRAY, smax));
-  // This fails, thus the call to FormatStatValue(.., const char*) was deprecated.
-  // ASSERT_EQ(smax, FormatStatValue(Type::BYTE_ARRAY, smax.c_str()));
-
-  smin = std::string("abcdefgh");
-  smax = std::string("ijklmnop");
-  ASSERT_STREQ("abcdefgh", FormatStatValue(Type::FIXED_LEN_BYTE_ARRAY, smin).c_str());
-  ASSERT_STREQ("abcdefgh",
-               FormatStatValue(Type::FIXED_LEN_BYTE_ARRAY, smin.c_str()).c_str());
-  ASSERT_STREQ("ijklmnop", FormatStatValue(Type::FIXED_LEN_BYTE_ARRAY, smax).c_str());
-  ASSERT_STREQ("ijklmnop",
-               FormatStatValue(Type::FIXED_LEN_BYTE_ARRAY, smax.c_str()).c_str());
-#if !(defined(_WIN32) || defined(__CYGWIN__))
-#pragma GCC diagnostic pop
-#endif
-}
-
-}  // namespace parquet
diff --git a/src/parquet/types.cc b/src/parquet/types.cc
deleted file mode 100644
index 3120963..0000000
--- a/src/parquet/types.cc
+++ /dev/null
@@ -1,295 +0,0 @@
-// 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.
-
-#include <cstdint>
-#include <cstring>
-#include <sstream>
-#include <string>
-
-#include "parquet/types.h"
-
-namespace parquet {
-
-std::string FormatStatValue(Type::type parquet_type, const std::string& val) {
-  std::stringstream result;
-  switch (parquet_type) {
-    case Type::BOOLEAN:
-      result << reinterpret_cast<const bool*>(val.c_str())[0];
-      break;
-    case Type::INT32:
-      result << reinterpret_cast<const int32_t*>(val.c_str())[0];
-      break;
-    case Type::INT64:
-      result << reinterpret_cast<const int64_t*>(val.c_str())[0];
-      break;
-    case Type::DOUBLE:
-      result << reinterpret_cast<const double*>(val.c_str())[0];
-      break;
-    case Type::FLOAT:
-      result << reinterpret_cast<const float*>(val.c_str())[0];
-      break;
-    case Type::INT96: {
-      auto const i32_val = reinterpret_cast<const int32_t*>(val.c_str());
-      result << i32_val[0] << " " << i32_val[1] << " " << i32_val[2];
-      break;
-    }
-    case Type::BYTE_ARRAY: {
-      return val;
-    }
-    case Type::FIXED_LEN_BYTE_ARRAY: {
-      return val;
-    }
-    default:
-      break;
-  }
-  return result.str();
-}
-
-std::string FormatStatValue(Type::type parquet_type, const char* val) {
-  std::stringstream result;
-  switch (parquet_type) {
-    case Type::BOOLEAN:
-      result << reinterpret_cast<const bool*>(val)[0];
-      break;
-    case Type::INT32:
-      result << reinterpret_cast<const int32_t*>(val)[0];
-      break;
-    case Type::INT64:
-      result << reinterpret_cast<const int64_t*>(val)[0];
-      break;
-    case Type::DOUBLE:
-      result << reinterpret_cast<const double*>(val)[0];
-      break;
-    case Type::FLOAT:
-      result << reinterpret_cast<const float*>(val)[0];
-      break;
-    case Type::INT96: {
-      auto const i32_val = reinterpret_cast<const int32_t*>(val);
-      result << i32_val[0] << " " << i32_val[1] << " " << i32_val[2];
-      break;
-    }
-    case Type::BYTE_ARRAY: {
-      result << val;
-      break;
-    }
-    case Type::FIXED_LEN_BYTE_ARRAY: {
-      result << val;
-      break;
-    }
-    default:
-      break;
-  }
-  return result.str();
-}
-
-std::string EncodingToString(Encoding::type t) {
-  switch (t) {
-    case Encoding::PLAIN:
-      return "PLAIN";
-    case Encoding::PLAIN_DICTIONARY:
-      return "PLAIN_DICTIONARY";
-    case Encoding::RLE:
-      return "RLE";
-    case Encoding::BIT_PACKED:
-      return "BIT_PACKED";
-    case Encoding::DELTA_BINARY_PACKED:
-      return "DELTA_BINARY_PACKED";
-    case Encoding::DELTA_LENGTH_BYTE_ARRAY:
-      return "DELTA_LENGTH_BYTE_ARRAY";
-    case Encoding::DELTA_BYTE_ARRAY:
-      return "DELTA_BYTE_ARRAY";
-    case Encoding::RLE_DICTIONARY:
-      return "RLE_DICTIONARY";
-    default:
-      return "UNKNOWN";
-  }
-}
-
-std::string CompressionToString(Compression::type t) {
-  switch (t) {
-    case Compression::UNCOMPRESSED:
-      return "UNCOMPRESSED";
-    case Compression::SNAPPY:
-      return "SNAPPY";
-    case Compression::GZIP:
-      return "GZIP";
-    case Compression::LZO:
-      return "LZO";
-    case Compression::LZ4:
-      return "LZ4";
-    case Compression::ZSTD:
-      return "ZSTD";
-    default:
-      return "UNKNOWN";
-  }
-}
-
-std::string TypeToString(Type::type t) {
-  switch (t) {
-    case Type::BOOLEAN:
-      return "BOOLEAN";
-    case Type::INT32:
-      return "INT32";
-    case Type::INT64:
-      return "INT64";
-    case Type::INT96:
-      return "INT96";
-    case Type::FLOAT:
-      return "FLOAT";
-    case Type::DOUBLE:
-      return "DOUBLE";
-    case Type::BYTE_ARRAY:
-      return "BYTE_ARRAY";
-    case Type::FIXED_LEN_BYTE_ARRAY:
-      return "FIXED_LEN_BYTE_ARRAY";
-    default:
-      return "UNKNOWN";
-  }
-}
-
-std::string LogicalTypeToString(LogicalType::type t) {
-  switch (t) {
-    case LogicalType::NONE:
-      return "NONE";
-    case LogicalType::UTF8:
-      return "UTF8";
-    case LogicalType::MAP_KEY_VALUE:
-      return "MAP_KEY_VALUE";
-    case LogicalType::LIST:
-      return "LIST";
-    case LogicalType::ENUM:
-      return "ENUM";
-    case LogicalType::DECIMAL:
-      return "DECIMAL";
-    case LogicalType::DATE:
-      return "DATE";
-    case LogicalType::TIME_MILLIS:
-      return "TIME_MILLIS";
-    case LogicalType::TIME_MICROS:
-      return "TIME_MICROS";
-    case LogicalType::TIMESTAMP_MILLIS:
-      return "TIMESTAMP_MILLIS";
-    case LogicalType::TIMESTAMP_MICROS:
-      return "TIMESTAMP_MICROS";
-    case LogicalType::UINT_8:
-      return "UINT_8";
-    case LogicalType::UINT_16:
-      return "UINT_16";
-    case LogicalType::UINT_32:
-      return "UINT_32";
-    case LogicalType::UINT_64:
-      return "UINT_64";
-    case LogicalType::INT_8:
-      return "INT_8";
-    case LogicalType::INT_16:
-      return "INT_16";
-    case LogicalType::INT_32:
-      return "INT_32";
-    case LogicalType::INT_64:
-      return "INT_64";
-    case LogicalType::JSON:
-      return "JSON";
-    case LogicalType::BSON:
-      return "BSON";
-    case LogicalType::INTERVAL:
-      return "INTERVAL";
-    default:
-      return "UNKNOWN";
-  }
-}
-
-int GetTypeByteSize(Type::type parquet_type) {
-  switch (parquet_type) {
-    case Type::BOOLEAN:
-      return type_traits<BooleanType::type_num>::value_byte_size;
-    case Type::INT32:
-      return type_traits<Int32Type::type_num>::value_byte_size;
-    case Type::INT64:
-      return type_traits<Int64Type::type_num>::value_byte_size;
-    case Type::INT96:
-      return type_traits<Int96Type::type_num>::value_byte_size;
-    case Type::DOUBLE:
-      return type_traits<DoubleType::type_num>::value_byte_size;
-    case Type::FLOAT:
-      return type_traits<FloatType::type_num>::value_byte_size;
-    case Type::BYTE_ARRAY:
-      return type_traits<ByteArrayType::type_num>::value_byte_size;
-    case Type::FIXED_LEN_BYTE_ARRAY:
-      return type_traits<FLBAType::type_num>::value_byte_size;
-    default:
-      return 0;
-  }
-  return 0;
-}
-
-// Return the Sort Order of the Parquet Physical Types
-SortOrder::type DefaultSortOrder(Type::type primitive) {
-  switch (primitive) {
-    case Type::BOOLEAN:
-    case Type::INT32:
-    case Type::INT64:
-    case Type::FLOAT:
-    case Type::DOUBLE:
-      return SortOrder::SIGNED;
-    case Type::BYTE_ARRAY:
-    case Type::FIXED_LEN_BYTE_ARRAY:
-      return SortOrder::UNSIGNED;
-    case Type::INT96:
-      return SortOrder::UNKNOWN;
-  }
-  return SortOrder::UNKNOWN;
-}
-
-// Return the SortOrder of the Parquet Types using Logical or Physical Types
-SortOrder::type GetSortOrder(LogicalType::type converted, Type::type primitive) {
-  if (converted == LogicalType::NONE) return DefaultSortOrder(primitive);
-  switch (converted) {
-    case LogicalType::INT_8:
-    case LogicalType::INT_16:
-    case LogicalType::INT_32:
-    case LogicalType::INT_64:
-    case LogicalType::DATE:
-    case LogicalType::TIME_MICROS:
-    case LogicalType::TIME_MILLIS:
-    case LogicalType::TIMESTAMP_MICROS:
-    case LogicalType::TIMESTAMP_MILLIS:
-      return SortOrder::SIGNED;
-    case LogicalType::UINT_8:
-    case LogicalType::UINT_16:
-    case LogicalType::UINT_32:
-    case LogicalType::UINT_64:
-    case LogicalType::ENUM:
-    case LogicalType::UTF8:
-    case LogicalType::BSON:
-    case LogicalType::JSON:
-      return SortOrder::UNSIGNED;
-    case LogicalType::DECIMAL:
-    case LogicalType::LIST:
-    case LogicalType::MAP:
-    case LogicalType::MAP_KEY_VALUE:
-    case LogicalType::INTERVAL:
-    case LogicalType::NONE:  // required instead of default
-    case LogicalType::NA:    // required instead of default
-      return SortOrder::UNKNOWN;
-  }
-  return SortOrder::UNKNOWN;
-}
-
-ColumnOrder ColumnOrder::undefined_ = ColumnOrder(ColumnOrder::UNDEFINED);
-ColumnOrder ColumnOrder::type_defined_ = ColumnOrder(ColumnOrder::TYPE_DEFINED_ORDER);
-
-}  // namespace parquet
diff --git a/src/parquet/types.h b/src/parquet/types.h
deleted file mode 100644
index 10789cb..0000000
--- a/src/parquet/types.h
+++ /dev/null
@@ -1,316 +0,0 @@
-// 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.
-
-#ifndef PARQUET_TYPES_H
-#define PARQUET_TYPES_H
-
-#include <algorithm>
-#include <cstdint>
-#include <cstring>
-#include <iterator>
-#include <sstream>
-#include <string>
-
-#include "arrow/util/macros.h"
-
-#include "parquet/util/macros.h"
-#include "parquet/util/visibility.h"
-
-namespace parquet {
-
-// ----------------------------------------------------------------------
-// Metadata enums to match Thrift metadata
-//
-// The reason we maintain our own enums is to avoid transitive dependency on
-// the compiled Thrift headers (and thus thrift/Thrift.h) for users of the
-// public API. After building parquet-cpp, you should not need to include
-// Thrift headers in your application. This means some boilerplate to convert
-// between our types and Parquet's Thrift types.
-//
-// We can also add special values like NONE to distinguish between metadata
-// values being set and not set. As an example consider ConvertedType and
-// CompressionCodec
-
-// Mirrors parquet::Type
-struct Type {
-  enum type {
-    BOOLEAN = 0,
-    INT32 = 1,
-    INT64 = 2,
-    INT96 = 3,
-    FLOAT = 4,
-    DOUBLE = 5,
-    BYTE_ARRAY = 6,
-    FIXED_LEN_BYTE_ARRAY = 7
-  };
-};
-
-// Mirrors parquet::ConvertedType
-struct LogicalType {
-  enum type {
-    NONE,
-    UTF8,
-    MAP,
-    MAP_KEY_VALUE,
-    LIST,
-    ENUM,
-    DECIMAL,
-    DATE,
-    TIME_MILLIS,
-    TIME_MICROS,
-    TIMESTAMP_MILLIS,
-    TIMESTAMP_MICROS,
-    UINT_8,
-    UINT_16,
-    UINT_32,
-    UINT_64,
-    INT_8,
-    INT_16,
-    INT_32,
-    INT_64,
-    JSON,
-    BSON,
-    INTERVAL,
-    NA = 25
-  };
-};
-
-// Mirrors parquet::FieldRepetitionType
-struct Repetition {
-  enum type { REQUIRED = 0, OPTIONAL = 1, REPEATED = 2 };
-};
-
-// Data encodings. Mirrors parquet::Encoding
-struct Encoding {
-  enum type {
-    PLAIN = 0,
-    PLAIN_DICTIONARY = 2,
-    RLE = 3,
-    BIT_PACKED = 4,
-    DELTA_BINARY_PACKED = 5,
-    DELTA_LENGTH_BYTE_ARRAY = 6,
-    DELTA_BYTE_ARRAY = 7,
-    RLE_DICTIONARY = 8
-  };
-};
-
-// Compression, mirrors parquet::CompressionCodec
-struct Compression {
-  enum type { UNCOMPRESSED, SNAPPY, GZIP, LZO, BROTLI, LZ4, ZSTD };
-};
-
-struct Encryption {
-  enum type { AES_GCM_V1 = 0, AES_GCM_CTR_V1 = 1 };
-};
-
-// parquet::PageType
-struct PageType {
-  enum type { DATA_PAGE, INDEX_PAGE, DICTIONARY_PAGE, DATA_PAGE_V2 };
-};
-
-// Reference:
-// parquet-mr/parquet-hadoop/src/main/java/org/apache/parquet/
-//                            format/converter/ParquetMetadataConverter.java
-// Sort order for page and column statistics. Types are associated with sort
-// orders (e.g., UTF8 columns should use UNSIGNED) and column stats are
-// aggregated using a sort order. As of parquet-format version 2.3.1, the
-// order used to aggregate stats is always SIGNED and is not stored in the
-// Parquet file. These stats are discarded for types that need unsigned.
-// See PARQUET-686.
-struct SortOrder {
-  enum type { SIGNED, UNSIGNED, UNKNOWN };
-};
-
-class ColumnOrder {
- public:
-  enum type { UNDEFINED, TYPE_DEFINED_ORDER };
-  explicit ColumnOrder(ColumnOrder::type column_order) : column_order_(column_order) {}
-  // Default to Type Defined Order
-  ColumnOrder() : column_order_(type::TYPE_DEFINED_ORDER) {}
-  ColumnOrder::type get_order() { return column_order_; }
-
-  static ColumnOrder undefined_;
-  static ColumnOrder type_defined_;
-
- private:
-  ColumnOrder::type column_order_;
-};
-
-// ----------------------------------------------------------------------
-
-struct ByteArray {
-  ByteArray() : len(0), ptr(nullptr) {}
-  ByteArray(uint32_t len, const uint8_t* ptr) : len(len), ptr(ptr) {}
-  uint32_t len;
-  const uint8_t* ptr;
-};
-
-inline bool operator==(const ByteArray& left, const ByteArray& right) {
-  return left.len == right.len && 0 == std::memcmp(left.ptr, right.ptr, left.len);
-}
-
-inline bool operator!=(const ByteArray& left, const ByteArray& right) {
-  return !(left == right);
-}
-
-struct FixedLenByteArray {
-  FixedLenByteArray() : ptr(nullptr) {}
-  explicit FixedLenByteArray(const uint8_t* ptr) : ptr(ptr) {}
-  const uint8_t* ptr;
-};
-
-using FLBA = FixedLenByteArray;
-
-MANUALLY_ALIGNED_STRUCT(1) Int96 { uint32_t value[3]; };
-STRUCT_END(Int96, 12);
-
-inline bool operator==(const Int96& left, const Int96& right) {
-  return std::equal(left.value, left.value + 3, right.value);
-}
-
-inline bool operator!=(const Int96& left, const Int96& right) { return !(left == right); }
-
-static inline std::string ByteArrayToString(const ByteArray& a) {
-  return std::string(reinterpret_cast<const char*>(a.ptr), a.len);
-}
-
-static inline std::string Int96ToString(const Int96& a) {
-  std::ostringstream result;
-  std::copy(a.value, a.value + 3, std::ostream_iterator<uint32_t>(result, " "));
-  return result.str();
-}
-
-static inline std::string FixedLenByteArrayToString(const FixedLenByteArray& a, int len) {
-  std::ostringstream result;
-  std::copy(a.ptr, a.ptr + len, std::ostream_iterator<uint32_t>(result, " "));
-  return result.str();
-}
-
-template <Type::type TYPE>
-struct type_traits {};
-
-template <>
-struct type_traits<Type::BOOLEAN> {
-  using value_type = bool;
-
-  static constexpr int value_byte_size = 1;
-  static constexpr const char* printf_code = "d";
-};
-
-template <>
-struct type_traits<Type::INT32> {
-  using value_type = int32_t;
-
-  static constexpr int value_byte_size = 4;
-  static constexpr const char* printf_code = "d";
-};
-
-template <>
-struct type_traits<Type::INT64> {
-  using value_type = int64_t;
-
-  static constexpr int value_byte_size = 8;
-  static constexpr const char* printf_code = "ld";
-};
-
-template <>
-struct type_traits<Type::INT96> {
-  using value_type = Int96;
-
-  static constexpr int value_byte_size = 12;
-  static constexpr const char* printf_code = "s";
-};
-
-template <>
-struct type_traits<Type::FLOAT> {
-  using value_type = float;
-
-  static constexpr int value_byte_size = 4;
-  static constexpr const char* printf_code = "f";
-};
-
-template <>
-struct type_traits<Type::DOUBLE> {
-  using value_type = double;
-
-  static constexpr int value_byte_size = 8;
-  static constexpr const char* printf_code = "lf";
-};
-
-template <>
-struct type_traits<Type::BYTE_ARRAY> {
-  using value_type = ByteArray;
-
-  static constexpr int value_byte_size = sizeof(ByteArray);
-  static constexpr const char* printf_code = "s";
-};
-
-template <>
-struct type_traits<Type::FIXED_LEN_BYTE_ARRAY> {
-  using value_type = FixedLenByteArray;
-
-  static constexpr int value_byte_size = sizeof(FixedLenByteArray);
-  static constexpr const char* printf_code = "s";
-};
-
-template <Type::type TYPE>
-struct DataType {
-  using c_type = typename type_traits<TYPE>::value_type;
-  static constexpr Type::type type_num = TYPE;
-};
-
-using BooleanType = DataType<Type::BOOLEAN>;
-using Int32Type = DataType<Type::INT32>;
-using Int64Type = DataType<Type::INT64>;
-using Int96Type = DataType<Type::INT96>;
-using FloatType = DataType<Type::FLOAT>;
-using DoubleType = DataType<Type::DOUBLE>;
-using ByteArrayType = DataType<Type::BYTE_ARRAY>;
-using FLBAType = DataType<Type::FIXED_LEN_BYTE_ARRAY>;
-
-template <typename Type>
-inline std::string format_fwf(int width) {
-  std::stringstream ss;
-  ss << "%-" << width << type_traits<Type::type_num>::printf_code;
-  return ss.str();
-}
-
-PARQUET_EXPORT std::string CompressionToString(Compression::type t);
-
-PARQUET_EXPORT std::string EncodingToString(Encoding::type t);
-
-PARQUET_EXPORT std::string LogicalTypeToString(LogicalType::type t);
-
-PARQUET_EXPORT std::string TypeToString(Type::type t);
-
-PARQUET_EXPORT std::string FormatStatValue(Type::type parquet_type,
-                                           const std::string& val);
-
-/// \deprecated Since 1.5.0
-PARQUET_DEPRECATED("Use std::string instead of char* as input")
-PARQUET_EXPORT std::string FormatStatValue(Type::type parquet_type, const char* val);
-
-PARQUET_EXPORT int GetTypeByteSize(Type::type t);
-
-PARQUET_EXPORT SortOrder::type DefaultSortOrder(Type::type primitive);
-
-PARQUET_EXPORT SortOrder::type GetSortOrder(LogicalType::type converted,
-                                            Type::type primitive);
-
-}  // namespace parquet
-
-#endif  // PARQUET_TYPES_H
diff --git a/src/parquet/util/CMakeLists.txt b/src/parquet/util/CMakeLists.txt
deleted file mode 100644
index 7b13886..0000000
--- a/src/parquet/util/CMakeLists.txt
+++ /dev/null
@@ -1,49 +0,0 @@
-# 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.
-
-# Headers: util
-install(FILES
-  buffer-builder.h
-  comparison.h
-  logging.h
-  macros.h
-  memory.h
-  stopwatch.h
-  visibility.h
-  DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/parquet/util")
-
-if (PARQUET_BUILD_BENCHMARKS)
-  add_library(parquet_benchmark_main benchmark_main.cc)
-  if (APPLE)
-    target_link_libraries(parquet_benchmark_main
-      gbenchmark
-    )
-  elseif(WIN32)
-    target_link_libraries(parquet_benchmark_main
-      gbenchmark
-      shlwapi.lib # workaround for bug(?) in gbenchmark: unresolved external symbol __imp_SHGetValueA
-    )
-  else()
-    target_link_libraries(parquet_benchmark_main
-      gbenchmark
-      pthread
-    )
-  endif()
-endif()
-
-ADD_PARQUET_TEST(comparison-test)
-ADD_PARQUET_TEST(memory-test)
diff --git a/src/parquet/util/benchmark_main.cc b/src/parquet/util/benchmark_main.cc
deleted file mode 100644
index c9739af..0000000
--- a/src/parquet/util/benchmark_main.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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.
-
-#include "benchmark/benchmark.h"
-
-int main(int argc, char** argv) {
-  benchmark::Initialize(&argc, argv);
-  benchmark::RunSpecifiedBenchmarks();
-  return 0;
-}
diff --git a/src/parquet/util/buffer-builder.h b/src/parquet/util/buffer-builder.h
deleted file mode 100644
index 26f134e..0000000
--- a/src/parquet/util/buffer-builder.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// 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.
-
-// Initially imported from Impala on 2016-02-23
-
-#ifndef PARQUET_UTIL_BUFFER_BUILDER_H
-#define PARQUET_UTIL_BUFFER_BUILDER_H
-
-#include <stdlib.h>
-#include <cstdint>
-
-namespace parquet {
-
-/// Utility class to build an in-memory buffer.
-class BufferBuilder {
- public:
-  BufferBuilder(uint8_t* dst_buffer, int dst_len)
-      : buffer_(dst_buffer), capacity_(dst_len), size_(0) {}
-
-  BufferBuilder(char* dst_buffer, int dst_len)
-      : buffer_(reinterpret_cast<uint8_t*>(dst_buffer)), capacity_(dst_len), size_(0) {}
-
-  inline void Append(const void* buffer, int len) {
-    memcpy(buffer_ + size_, buffer, len);
-    size_ += len;
-  }
-
-  template <typename T>
-  inline void Append(const T& v) {
-    Append(&v, sizeof(T));
-  }
-
-  int capacity() const { return capacity_; }
-  int size() const { return size_; }
-
- private:
-  uint8_t* buffer_;
-  int capacity_;
-  int size_;
-};
-
-}  // namespace parquet
-
-#endif  // PARQUET_UTIL_BUFFER_BUILDER_H
diff --git a/src/parquet/util/comparison-test.cc b/src/parquet/util/comparison-test.cc
deleted file mode 100644
index c05f934..0000000
--- a/src/parquet/util/comparison-test.cc
+++ /dev/null
@@ -1,247 +0,0 @@
-// 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.
-
-#include <gtest/gtest.h>
-
-#include <cstdint>
-#include <iostream>
-#include <vector>
-
-#include "parquet/schema.h"
-#include "parquet/types.h"
-#include "parquet/util/comparison.h"
-
-namespace parquet {
-
-namespace test {
-
-using parquet::schema::NodePtr;
-using parquet::schema::PrimitiveNode;
-
-static ByteArray ByteArrayFromString(const std::string& s) {
-  auto ptr = reinterpret_cast<const uint8_t*>(s.data());
-  return ByteArray(static_cast<uint32_t>(s.size()), ptr);
-}
-
-static FLBA FLBAFromString(const std::string& s) {
-  auto ptr = reinterpret_cast<const uint8_t*>(s.data());
-  return FLBA(ptr);
-}
-
-TEST(Comparison, signedByteArray) {
-  NodePtr node =
-      PrimitiveNode::Make("SignedByteArray", Repetition::REQUIRED, Type::BYTE_ARRAY);
-  ColumnDescriptor descr(node, 0, 0);
-
-  CompareDefaultByteArray less;
-
-  std::string s1 = "12345";
-  std::string s2 = "12345678";
-  ByteArray s1ba = ByteArrayFromString(s1);
-  ByteArray s2ba = ByteArrayFromString(s2);
-  ASSERT_TRUE(less(s1ba, s2ba));
-
-  // This is case where signed comparision UTF-8 (PARQUET-686) is incorrect
-  // This example is to only check signed comparison and not UTF-8.
-  s1 = u8"bügeln";
-  s2 = u8"braten";
-  s1ba = ByteArrayFromString(s1);
-  s2ba = ByteArrayFromString(s2);
-  ASSERT_TRUE(less(s1ba, s2ba));
-}
-
-TEST(Comparison, UnsignedByteArray) {
-  NodePtr node = PrimitiveNode::Make("UnsignedByteArray", Repetition::REQUIRED,
-                                     Type::BYTE_ARRAY, LogicalType::UTF8);
-  ColumnDescriptor descr(node, 0, 0);
-
-  // Check if UTF-8 is compared using unsigned correctly
-  CompareUnsignedByteArray uless;
-
-  std::string s1 = "arrange";
-  std::string s2 = "arrangement";
-  ByteArray s1ba = ByteArrayFromString(s1);
-  ByteArray s2ba = ByteArrayFromString(s2);
-  ASSERT_TRUE(uless(s1ba, s2ba));
-
-  // Multi-byte UTF-8 characters
-  s1 = u8"braten";
-  s2 = u8"bügeln";
-  s1ba = ByteArrayFromString(s1);
-  s2ba = ByteArrayFromString(s2);
-  ASSERT_TRUE(uless(s1ba, s2ba));
-
-  s1 = u8"ünk123456";  // ü = 252
-  s2 = u8"ănk123456";  // ă = 259
-  s1ba = ByteArrayFromString(s1);
-  s2ba = ByteArrayFromString(s2);
-  ASSERT_TRUE(uless(s1ba, s2ba));
-}
-
-TEST(Comparison, SignedFLBA) {
-  int size = 10;
-  NodePtr node = PrimitiveNode::Make("SignedFLBA", Repetition::REQUIRED,
-                                     Type::FIXED_LEN_BYTE_ARRAY, LogicalType::NONE, size);
-  ColumnDescriptor descr(node, 0, 0);
-
-  CompareDefaultFLBA less(descr.type_length());
-
-  std::string s1 = "Anti123456";
-  std::string s2 = "Bunkd123456";
-  FLBA s1flba = FLBAFromString(s1);
-  FLBA s2flba = FLBAFromString(s2);
-  ASSERT_TRUE(less(s1flba, s2flba));
-
-  s1 = "Bünk123456";
-  s2 = "Bunk123456";
-  s1flba = FLBAFromString(s1);
-  s2flba = FLBAFromString(s2);
-  ASSERT_TRUE(less(s1flba, s2flba));
-}
-
-TEST(Comparison, UnsignedFLBA) {
-  int size = 10;
-  NodePtr node = PrimitiveNode::Make("UnsignedFLBA", Repetition::REQUIRED,
-                                     Type::FIXED_LEN_BYTE_ARRAY, LogicalType::NONE, size);
-  ColumnDescriptor descr(node, 0, 0);
-
-  CompareUnsignedFLBA uless(descr.type_length());
-
-  std::string s1 = "Anti123456";
-  std::string s2 = "Bunkd123456";
-  FLBA s1flba = FLBAFromString(s1);
-  FLBA s2flba = FLBAFromString(s2);
-  ASSERT_TRUE(uless(s1flba, s2flba));
-
-  s1 = "Bunk123456";
-  s2 = "Bünk123456";
-  s1flba = FLBAFromString(s1);
-  s2flba = FLBAFromString(s2);
-  ASSERT_TRUE(uless(s1flba, s2flba));
-}
-
-TEST(Comparison, SignedInt96) {
-  parquet::Int96 a{{1, 41, 14}}, b{{1, 41, 42}};
-  parquet::Int96 aa{{1, 41, 14}}, bb{{1, 41, 14}};
-  parquet::Int96 aaa{{1, 41, static_cast<uint32_t>(-14)}}, bbb{{1, 41, 42}};
-
-  NodePtr node = PrimitiveNode::Make("SignedInt96", Repetition::REQUIRED, Type::INT96);
-  ColumnDescriptor descr(node, 0, 0);
-
-  CompareDefaultInt96 less;
-
-  ASSERT_TRUE(less(a, b));
-  ASSERT_TRUE(!less(aa, bb) && !less(bb, aa));
-  ASSERT_TRUE(less(aaa, bbb));
-}
-
-TEST(Comparison, UnsignedInt96) {
-  parquet::Int96 a{{1, 41, 14}}, b{{1, static_cast<uint32_t>(-41), 42}};
-  parquet::Int96 aa{{1, 41, 14}}, bb{{1, 41, static_cast<uint32_t>(-14)}};
-  parquet::Int96 aaa, bbb;
-
-  NodePtr node = PrimitiveNode::Make("UnsignedInt96", Repetition::REQUIRED, Type::INT96);
-  ColumnDescriptor descr(node, 0, 0);
-
-  CompareUnsignedInt96 uless;
-
-  ASSERT_TRUE(uless(a, b));
-  ASSERT_TRUE(uless(aa, bb));
-
-  // INT96 Timestamp
-  aaa.value[2] = 2451545;  // 2000-01-01
-  bbb.value[2] = 2451546;  // 2000-01-02
-  // 12 hours + 34 minutes + 56 seconds.
-  reinterpret_cast<uint64_t*>(&aaa.value[0])[0] = 45296000000000;
-  // 12 hours + 34 minutes + 50 seconds.
-  reinterpret_cast<uint64_t*>(&bbb.value[0])[0] = 45290000000000;
-  ASSERT_TRUE(uless(aaa, bbb));
-
-  aaa.value[2] = 2451545;  // 2000-01-01
-  bbb.value[2] = 2451545;  // 2000-01-01
-  // 11 hours + 34 minutes + 56 seconds.
-  reinterpret_cast<uint64_t*>(&aaa.value[0])[0] = 41696000000000;
-  // 12 hours + 34 minutes + 50 seconds.
-  reinterpret_cast<uint64_t*>(&bbb.value[0])[0] = 45290000000000;
-  ASSERT_TRUE(uless(aaa, bbb));
-
-  aaa.value[2] = 2451545;  // 2000-01-01
-  bbb.value[2] = 2451545;  // 2000-01-01
-  // 12 hours + 34 minutes + 55 seconds.
-  reinterpret_cast<uint64_t*>(&aaa.value[0])[0] = 45295000000000;
-  // 12 hours + 34 minutes + 56 seconds.
-  reinterpret_cast<uint64_t*>(&bbb.value[0])[0] = 45296000000000;
-  ASSERT_TRUE(uless(aaa, bbb));
-}
-
-TEST(Comparison, SignedInt64) {
-  int64_t a = 1, b = 4;
-  int64_t aa = 1, bb = 1;
-  int64_t aaa = -1, bbb = 1;
-
-  NodePtr node = PrimitiveNode::Make("SignedInt64", Repetition::REQUIRED, Type::INT64);
-  ColumnDescriptor descr(node, 0, 0);
-
-  CompareDefaultInt64 less;
-
-  ASSERT_TRUE(less(a, b));
-  ASSERT_TRUE(!less(aa, bb) && !less(bb, aa));
-  ASSERT_TRUE(less(aaa, bbb));
-}
-
-TEST(Comparison, UnsignedInt64) {
-  uint64_t a = 1, b = 4;
-  uint64_t aa = 1, bb = 1;
-  uint64_t aaa = 1, bbb = -1;
-
-  NodePtr node = PrimitiveNode::Make("UnsignedInt64", Repetition::REQUIRED, Type::INT64);
-  ColumnDescriptor descr(node, 0, 0);
-
-  CompareUnsignedInt64 less;
-
-  ASSERT_TRUE(less(a, b));
-  ASSERT_TRUE(!less(aa, bb) && !less(bb, aa));
-  ASSERT_TRUE(less(aaa, bbb));
-}
-
-TEST(Comparison, UnsignedInt32) {
-  uint32_t a = 1, b = 4;
-  uint32_t aa = 1, bb = 1;
-  uint32_t aaa = 1, bbb = -1;
-
-  NodePtr node = PrimitiveNode::Make("UnsignedInt32", Repetition::REQUIRED, Type::INT32);
-  ColumnDescriptor descr(node, 0, 0);
-
-  CompareUnsignedInt32 less;
-
-  ASSERT_TRUE(less(a, b));
-  ASSERT_TRUE(!less(aa, bb) && !less(bb, aa));
-  ASSERT_TRUE(less(aaa, bbb));
-}
-
-TEST(Comparison, UnknownSortOrder) {
-  NodePtr node =
-      PrimitiveNode::Make("Unknown", Repetition::REQUIRED, Type::FIXED_LEN_BYTE_ARRAY,
-                          LogicalType::INTERVAL, 12);
-  ColumnDescriptor descr(node, 0, 0);
-
-  ASSERT_THROW(Comparator::Make(&descr), ParquetException);
-}
-
-}  // namespace test
-
-}  // namespace parquet
diff --git a/src/parquet/util/comparison.cc b/src/parquet/util/comparison.cc
deleted file mode 100644
index a0768b3..0000000
--- a/src/parquet/util/comparison.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-// 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.
-
-#include <algorithm>
-
-#include "parquet/exception.h"
-#include "parquet/schema.h"
-#include "parquet/types.h"
-#include "parquet/util/comparison.h"
-
-namespace parquet {
-
-std::shared_ptr<Comparator> Comparator::Make(const ColumnDescriptor* descr) {
-  if (SortOrder::SIGNED == descr->sort_order()) {
-    switch (descr->physical_type()) {
-      case Type::BOOLEAN:
-        return std::make_shared<CompareDefaultBoolean>();
-      case Type::INT32:
-        return std::make_shared<CompareDefaultInt32>();
-      case Type::INT64:
-        return std::make_shared<CompareDefaultInt64>();
-      case Type::FLOAT:
-        return std::make_shared<CompareDefaultFloat>();
-      case Type::DOUBLE:
-        return std::make_shared<CompareDefaultDouble>();
-      case Type::BYTE_ARRAY:
-        return std::make_shared<CompareDefaultByteArray>();
-      case Type::FIXED_LEN_BYTE_ARRAY:
-        return std::make_shared<CompareDefaultFLBA>(descr->type_length());
-      default:
-        ParquetException::NYI("Signed Compare not implemented");
-    }
-  } else if (SortOrder::UNSIGNED == descr->sort_order()) {
-    switch (descr->physical_type()) {
-      case Type::INT32:
-        return std::make_shared<CompareUnsignedInt32>();
-      case Type::INT64:
-        return std::make_shared<CompareUnsignedInt64>();
-      case Type::BYTE_ARRAY:
-        return std::make_shared<CompareUnsignedByteArray>();
-      case Type::FIXED_LEN_BYTE_ARRAY:
-        return std::make_shared<CompareUnsignedFLBA>(descr->type_length());
-      default:
-        ParquetException::NYI("Unsigned Compare not implemented");
-    }
-  } else {
-    throw ParquetException("UNKNOWN Sort Order");
-  }
-  return nullptr;
-}
-
-template class PARQUET_TEMPLATE_EXPORT CompareDefault<BooleanType>;
-template class PARQUET_TEMPLATE_EXPORT CompareDefault<Int32Type>;
-template class PARQUET_TEMPLATE_EXPORT CompareDefault<Int64Type>;
-template class PARQUET_TEMPLATE_EXPORT CompareDefault<Int96Type>;
-template class PARQUET_TEMPLATE_EXPORT CompareDefault<FloatType>;
-template class PARQUET_TEMPLATE_EXPORT CompareDefault<DoubleType>;
-template class PARQUET_TEMPLATE_EXPORT CompareDefault<ByteArrayType>;
-template class PARQUET_TEMPLATE_EXPORT CompareDefault<FLBAType>;
-
-}  // namespace parquet
diff --git a/src/parquet/util/comparison.h b/src/parquet/util/comparison.h
deleted file mode 100644
index 7070a0f..0000000
--- a/src/parquet/util/comparison.h
+++ /dev/null
@@ -1,166 +0,0 @@
-// 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.
-
-#ifndef PARQUET_UTIL_COMPARISON_H
-#define PARQUET_UTIL_COMPARISON_H
-
-#include <algorithm>
-
-#include "parquet/exception.h"
-#include "parquet/schema.h"
-#include "parquet/types.h"
-
-namespace parquet {
-
-class PARQUET_EXPORT Comparator {
- public:
-  virtual ~Comparator() {}
-  static std::shared_ptr<Comparator> Make(const ColumnDescriptor* descr);
-};
-
-// The default comparison is SIGNED
-template <typename DType>
-class PARQUET_EXPORT CompareDefault : public Comparator {
- public:
-  typedef typename DType::c_type T;
-  CompareDefault() {}
-  virtual bool operator()(const T& a, const T& b) { return a < b; }
-};
-
-template <>
-class PARQUET_EXPORT CompareDefault<Int96Type> : public Comparator {
- public:
-  CompareDefault() {}
-  virtual bool operator()(const Int96& a, const Int96& b) {
-    // Only the MSB bit is by Signed comparison
-    // For little-endian, this is the last bit of Int96 type
-    const int32_t amsb = static_cast<const int32_t>(a.value[2]);
-    const int32_t bmsb = static_cast<const int32_t>(b.value[2]);
-    if (amsb != bmsb) {
-      return (amsb < bmsb);
-    } else if (a.value[1] != b.value[1]) {
-      return (a.value[1] < b.value[1]);
-    }
-    return (a.value[0] < b.value[0]);
-  }
-};
-
-template <>
-class PARQUET_EXPORT CompareDefault<ByteArrayType> : public Comparator {
- public:
-  CompareDefault() {}
-  virtual bool operator()(const ByteArray& a, const ByteArray& b) {
-    const int8_t* aptr = reinterpret_cast<const int8_t*>(a.ptr);
-    const int8_t* bptr = reinterpret_cast<const int8_t*>(b.ptr);
-    return std::lexicographical_compare(aptr, aptr + a.len, bptr, bptr + b.len);
-  }
-};
-
-template <>
-class PARQUET_EXPORT CompareDefault<FLBAType> : public Comparator {
- public:
-  explicit CompareDefault(int length) : type_length_(length) {}
-  virtual bool operator()(const FLBA& a, const FLBA& b) {
-    const int8_t* aptr = reinterpret_cast<const int8_t*>(a.ptr);
-    const int8_t* bptr = reinterpret_cast<const int8_t*>(b.ptr);
-    return std::lexicographical_compare(aptr, aptr + type_length_, bptr,
-                                        bptr + type_length_);
-  }
-  int32_t type_length_;
-};
-
-typedef CompareDefault<BooleanType> CompareDefaultBoolean;
-typedef CompareDefault<Int32Type> CompareDefaultInt32;
-typedef CompareDefault<Int64Type> CompareDefaultInt64;
-typedef CompareDefault<Int96Type> CompareDefaultInt96;
-typedef CompareDefault<FloatType> CompareDefaultFloat;
-typedef CompareDefault<DoubleType> CompareDefaultDouble;
-typedef CompareDefault<ByteArrayType> CompareDefaultByteArray;
-typedef CompareDefault<FLBAType> CompareDefaultFLBA;
-
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wattributes"
-#endif
-
-PARQUET_EXTERN_TEMPLATE CompareDefault<BooleanType>;
-PARQUET_EXTERN_TEMPLATE CompareDefault<Int32Type>;
-PARQUET_EXTERN_TEMPLATE CompareDefault<Int64Type>;
-PARQUET_EXTERN_TEMPLATE CompareDefault<Int96Type>;
-PARQUET_EXTERN_TEMPLATE CompareDefault<FloatType>;
-PARQUET_EXTERN_TEMPLATE CompareDefault<DoubleType>;
-PARQUET_EXTERN_TEMPLATE CompareDefault<ByteArrayType>;
-PARQUET_EXTERN_TEMPLATE CompareDefault<FLBAType>;
-
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-
-// Define Unsigned Comparators
-class PARQUET_EXPORT CompareUnsignedInt32 : public CompareDefaultInt32 {
- public:
-  bool operator()(const int32_t& a, const int32_t& b) override {
-    const uint32_t ua = a;
-    const uint32_t ub = b;
-    return (ua < ub);
-  }
-};
-
-class PARQUET_EXPORT CompareUnsignedInt64 : public CompareDefaultInt64 {
- public:
-  bool operator()(const int64_t& a, const int64_t& b) override {
-    const uint64_t ua = a;
-    const uint64_t ub = b;
-    return (ua < ub);
-  }
-};
-
-class PARQUET_EXPORT CompareUnsignedInt96 : public CompareDefaultInt96 {
- public:
-  bool operator()(const Int96& a, const Int96& b) override {
-    if (a.value[2] != b.value[2]) {
-      return (a.value[2] < b.value[2]);
-    } else if (a.value[1] != b.value[1]) {
-      return (a.value[1] < b.value[1]);
-    }
-    return (a.value[0] < b.value[0]);
-  }
-};
-
-class PARQUET_EXPORT CompareUnsignedByteArray : public CompareDefaultByteArray {
- public:
-  bool operator()(const ByteArray& a, const ByteArray& b) override {
-    const uint8_t* aptr = reinterpret_cast<const uint8_t*>(a.ptr);
-    const uint8_t* bptr = reinterpret_cast<const uint8_t*>(b.ptr);
-    return std::lexicographical_compare(aptr, aptr + a.len, bptr, bptr + b.len);
-  }
-};
-
-class PARQUET_EXPORT CompareUnsignedFLBA : public CompareDefaultFLBA {
- public:
-  explicit CompareUnsignedFLBA(int length) : CompareDefaultFLBA(length) {}
-  bool operator()(const FLBA& a, const FLBA& b) override {
-    const uint8_t* aptr = reinterpret_cast<const uint8_t*>(a.ptr);
-    const uint8_t* bptr = reinterpret_cast<const uint8_t*>(b.ptr);
-    return std::lexicographical_compare(aptr, aptr + type_length_, bptr,
-                                        bptr + type_length_);
-  }
-};
-
-}  // namespace parquet
-
-#endif  // PARQUET_UTIL_COMPARISON_H
diff --git a/src/parquet/util/crypto.cc b/src/parquet/util/crypto.cc
deleted file mode 100644
index 59383d1..0000000
--- a/src/parquet/util/crypto.cc
+++ /dev/null
@@ -1,369 +0,0 @@
-// 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.
-
-#include "parquet/util/crypto.h"
-#include <openssl/aes.h>
-#include <openssl/evp.h>
-#include <openssl/rand.h>
-#include <algorithm>
-#include <iostream>
-#include <memory>
-#include <sstream>
-#include <string>
-#include "parquet/exception.h"
-
-using parquet::ParquetException;
-
-namespace parquet_encryption {
-
-constexpr int aesGcm = 0;
-constexpr int aesCtr = 1;
-constexpr int encryptType = 0;
-constexpr int decryptType = 1;
-constexpr int gcmTagLen = 16;
-constexpr int gcmIvLen = 12;
-constexpr int ctrIvLen = 16;
-constexpr int rndMaxBytes = 32;
-
-#define ENCRYPT_INIT(CTX, ALG)                                        \
-  if (1 != EVP_EncryptInit_ex(CTX, ALG, nullptr, nullptr, nullptr)) { \
-    throw ParquetException("Couldn't init ALG encryption");           \
-  }
-
-#define DECRYPT_INIT(CTX, ALG)                                        \
-  if (1 != EVP_DecryptInit_ex(CTX, ALG, nullptr, nullptr, nullptr)) { \
-    throw ParquetException("Couldn't init ALG decryption");           \
-  }
-
-class EvpCipher {
- public:
-  explicit EvpCipher(int cipher, int key_len, int type) {
-    ctx_ = nullptr;
-
-    if (aesGcm != cipher && aesCtr != cipher) {
-      std::stringstream ss;
-      ss << "Wrong cipher: " << cipher;
-      throw ParquetException(ss.str());
-    }
-
-    if (16 != key_len && 24 != key_len && 32 != key_len) {
-      std::stringstream ss;
-      ss << "Wrong key length: " << key_len;
-      throw ParquetException(ss.str());
-    }
-
-    if (encryptType != type && decryptType != type) {
-      std::stringstream ss;
-      ss << "Wrong cipher type: " << type;
-      throw ParquetException(ss.str());
-    }
-
-    ctx_ = EVP_CIPHER_CTX_new();
-    if (nullptr == ctx_) {
-      throw ParquetException("Couldn't init cipher context");
-    }
-
-    if (aesGcm == cipher) {
-      // Init AES-GCM with specified key length
-      if (16 == key_len) {
-        if (encryptType == type) {
-          ENCRYPT_INIT(ctx_, EVP_aes_128_gcm());
-        } else {
-          DECRYPT_INIT(ctx_, EVP_aes_128_gcm());
-        }
-      } else if (24 == key_len) {
-        if (encryptType == type) {
-          ENCRYPT_INIT(ctx_, EVP_aes_192_gcm());
-        } else {
-          DECRYPT_INIT(ctx_, EVP_aes_192_gcm());
-        }
-      } else if (32 == key_len) {
-        if (encryptType == type) {
-          ENCRYPT_INIT(ctx_, EVP_aes_256_gcm());
-        } else {
-          DECRYPT_INIT(ctx_, EVP_aes_256_gcm());
-        }
-      }
-    } else {
-      // Init AES-CTR with specified key length
-      if (16 == key_len) {
-        if (encryptType == type) {
-          ENCRYPT_INIT(ctx_, EVP_aes_128_ctr());
-        } else {
-          DECRYPT_INIT(ctx_, EVP_aes_128_ctr());
-        }
-      } else if (24 == key_len) {
-        if (encryptType == type) {
-          ENCRYPT_INIT(ctx_, EVP_aes_192_ctr());
-        } else {
-          DECRYPT_INIT(ctx_, EVP_aes_192_ctr());
-        }
-      } else if (32 == key_len) {
-        if (encryptType == type) {
-          ENCRYPT_INIT(ctx_, EVP_aes_256_ctr());
-        } else {
-          DECRYPT_INIT(ctx_, EVP_aes_256_ctr());
-        }
-      }
-    }
-  }
-
-  EVP_CIPHER_CTX* get() { return ctx_; }
-
-  ~EvpCipher() {
-    if (nullptr != ctx_) {
-      EVP_CIPHER_CTX_free(ctx_);
-    }
-  }
-
- private:
-  EVP_CIPHER_CTX* ctx_;
-};
-
-int gcm_encrypt(const uint8_t* plaintext, int plaintext_len, uint8_t* key, int key_len,
-                uint8_t* aad, int aad_len, uint8_t* ciphertext) {
-  int len;
-  int ciphertext_len;
-
-  uint8_t tag[gcmTagLen];
-  memset(tag, 0, gcmTagLen);
-  uint8_t iv[gcmIvLen];
-  memset(iv, 0, gcmIvLen);
-
-  // Random IV
-  RAND_load_file("/dev/urandom", rndMaxBytes);
-  RAND_bytes(iv, sizeof(iv));
-
-  // Init cipher context
-  EvpCipher cipher(aesGcm, key_len, encryptType);
-
-  // Setting key and IV
-  if (1 != EVP_EncryptInit_ex(cipher.get(), nullptr, nullptr, key, iv)) {
-    throw ParquetException("Couldn't set key and IV");
-  }
-
-  // Setting additional authenticated data
-  if ((nullptr != aad) &&
-      (1 != EVP_EncryptUpdate(cipher.get(), nullptr, &len, aad, aad_len))) {
-    throw ParquetException("Couldn't set AAD");
-  }
-
-  // Encryption
-  if (1 != EVP_EncryptUpdate(cipher.get(), ciphertext + gcmIvLen, &len, plaintext,
-                             plaintext_len)) {
-    throw ParquetException("Failed encryption update");
-  }
-
-  ciphertext_len = len;
-
-  // Finalization
-  if (1 != EVP_EncryptFinal_ex(cipher.get(), ciphertext + gcmIvLen + len, &len)) {
-    throw ParquetException("Failed encryption finalization");
-  }
-
-  ciphertext_len += len;
-
-  // Getting the tag
-  if (1 != EVP_CIPHER_CTX_ctrl(cipher.get(), EVP_CTRL_GCM_GET_TAG, gcmTagLen, tag)) {
-    throw ParquetException("Couldn't get AES-GCM tag");
-  }
-
-  // Copying the IV and tag to ciphertext
-  std::copy(iv, iv + gcmIvLen, ciphertext);
-  std::copy(tag, tag + gcmTagLen, ciphertext + gcmIvLen + ciphertext_len);
-
-  return gcmIvLen + ciphertext_len + gcmTagLen;
-}
-
-int ctr_encrypt(const uint8_t* plaintext, int plaintext_len, uint8_t* key, int key_len,
-                uint8_t* ciphertext) {
-  int len;
-  int ciphertext_len;
-
-  uint8_t iv[ctrIvLen];
-  memset(iv, 0, ctrIvLen);
-
-  // Random IV
-  RAND_load_file("/dev/urandom", rndMaxBytes);
-  RAND_bytes(iv, sizeof(iv));
-
-  // Init cipher context
-  EvpCipher cipher(aesCtr, key_len, encryptType);
-
-  // Setting key and IV
-  if (1 != EVP_EncryptInit_ex(cipher.get(), nullptr, nullptr, key, iv)) {
-    throw ParquetException("Couldn't set key and IV");
-  }
-
-  // Encryption
-  if (1 != EVP_EncryptUpdate(cipher.get(), ciphertext + ctrIvLen, &len, plaintext,
-                             plaintext_len)) {
-    throw ParquetException("Failed encryption update");
-  }
-
-  ciphertext_len = len;
-
-  // Finalization
-  if (1 != EVP_EncryptFinal_ex(cipher.get(), ciphertext + ctrIvLen + len, &len)) {
-    throw ParquetException("Failed encryption finalization");
-  }
-
-  ciphertext_len += len;
-
-  // Copying the IV ciphertext
-  std::copy(iv, iv + ctrIvLen, ciphertext);
-
-  return ctrIvLen + ciphertext_len;
-}
-
-int Encrypt(Encryption::type alg_id, bool metadata, const uint8_t* plaintext,
-            int plaintext_len, uint8_t* key, int key_len, uint8_t* aad, int aad_len,
-            uint8_t* ciphertext) {
-  if (Encryption::AES_GCM_V1 != alg_id && Encryption::AES_GCM_CTR_V1 != alg_id) {
-    std::stringstream ss;
-    ss << "Crypto algorithm " << alg_id << " is not supported";
-    throw ParquetException(ss.str());
-  }
-
-  if (metadata || (Encryption::AES_GCM_V1 == alg_id)) {
-    return gcm_encrypt(plaintext, plaintext_len, key, key_len, aad, aad_len, ciphertext);
-  }
-
-  // Data (page) encryption with AES_GCM_CTR_V1
-  return ctr_encrypt(plaintext, plaintext_len, key, key_len, ciphertext);
-}
-
-int Encrypt(std::shared_ptr<EncryptionProperties> encryption_props, bool metadata,
-            const uint8_t* plaintext, int plaintext_len, uint8_t* ciphertext) {
-  return Encrypt(encryption_props->algorithm(), metadata, plaintext, plaintext_len,
-                 encryption_props->key_bytes(), encryption_props->key_length(),
-                 encryption_props->aad_bytes(), encryption_props->aad_length(),
-                 ciphertext);
-}
-
-int gcm_decrypt(const uint8_t* ciphertext, int ciphertext_len, uint8_t* key, int key_len,
-                uint8_t* aad, int aad_len, uint8_t* plaintext) {
-  int len;
-  int plaintext_len;
-
-  uint8_t tag[gcmTagLen];
-  memset(tag, 0, gcmTagLen);
-  uint8_t iv[gcmIvLen];
-  memset(iv, 0, gcmIvLen);
-
-  // Extracting IV and tag
-  std::copy(ciphertext, ciphertext + gcmIvLen, iv);
-  std::copy(ciphertext + ciphertext_len - gcmTagLen, ciphertext + ciphertext_len, tag);
-
-  // Init cipher context
-  EvpCipher cipher(aesGcm, key_len, decryptType);
-
-  // Setting key and IV
-  if (1 != EVP_DecryptInit_ex(cipher.get(), nullptr, nullptr, key, iv)) {
-    throw ParquetException("Couldn't set key and IV");
-  }
-
-  // Setting additional authenticated data
-  if ((nullptr != aad) &&
-      (1 != EVP_DecryptUpdate(cipher.get(), nullptr, &len, aad, aad_len))) {
-    throw ParquetException("Couldn't set AAD");
-  }
-
-  // Decryption
-  if (!EVP_DecryptUpdate(cipher.get(), plaintext, &len, ciphertext + gcmIvLen,
-                         ciphertext_len - gcmIvLen - gcmTagLen)) {
-    throw ParquetException("Failed decryption update");
-  }
-
-  plaintext_len = len;
-
-  // Checking the tag (authentication)
-  if (!EVP_CIPHER_CTX_ctrl(cipher.get(), EVP_CTRL_GCM_SET_TAG, gcmTagLen, tag)) {
-    throw ParquetException("Failed authentication");
-  }
-
-  // Finalization
-  if (1 != EVP_DecryptFinal_ex(cipher.get(), plaintext + len, &len)) {
-    throw ParquetException("Failed decryption finalization");
-  }
-
-  plaintext_len += len;
-  return plaintext_len;
-}
-
-int ctr_decrypt(const uint8_t* ciphertext, int ciphertext_len, uint8_t* key, int key_len,
-                uint8_t* plaintext) {
-  int len;
-  int plaintext_len;
-
-  uint8_t iv[ctrIvLen];
-  memset(iv, 0, ctrIvLen);
-
-  // Extracting IV and tag
-  std::copy(ciphertext, ciphertext + ctrIvLen, iv);
-
-  // Init cipher context
-  EvpCipher cipher(aesCtr, key_len, decryptType);
-
-  // Setting key and IV
-  if (1 != EVP_DecryptInit_ex(cipher.get(), nullptr, nullptr, key, iv)) {
-    throw ParquetException("Couldn't set key and IV");
-  }
-
-  // Decryption
-  if (!EVP_DecryptUpdate(cipher.get(), plaintext, &len, ciphertext + ctrIvLen,
-                         ciphertext_len - ctrIvLen)) {
-    throw ParquetException("Failed decryption update");
-  }
-
-  plaintext_len = len;
-
-  // Finalization
-  if (1 != EVP_DecryptFinal_ex(cipher.get(), plaintext + len, &len)) {
-    throw ParquetException("Failed decryption finalization");
-  }
-
-  plaintext_len += len;
-  return plaintext_len;
-}
-
-int Decrypt(Encryption::type alg_id, bool metadata, const uint8_t* ciphertext,
-            int ciphertext_len, uint8_t* key, int key_len, uint8_t* aad, int aad_len,
-            uint8_t* plaintext) {
-  if (Encryption::AES_GCM_V1 != alg_id && Encryption::AES_GCM_CTR_V1 != alg_id) {
-    std::stringstream ss;
-    ss << "Crypto algorithm " << alg_id << " is not supported";
-    throw ParquetException(ss.str());
-  }
-
-  if (metadata || (Encryption::AES_GCM_V1 == alg_id)) {
-    return gcm_decrypt(ciphertext, ciphertext_len, key, key_len, aad, aad_len, plaintext);
-  }
-
-  // Data (page) decryption with AES_GCM_CTR_V1
-  return ctr_decrypt(ciphertext, ciphertext_len, key, key_len, plaintext);
-}
-
-int Decrypt(std::shared_ptr<EncryptionProperties> encryption_props, bool metadata,
-            const uint8_t* ciphertext, int ciphertext_len, uint8_t* plaintext) {
-  return Decrypt(encryption_props->algorithm(), metadata, ciphertext, ciphertext_len,
-                 encryption_props->key_bytes(), encryption_props->key_length(),
-                 encryption_props->aad_bytes(), encryption_props->aad_length(),
-                 plaintext);
-}
-
-}  // namespace parquet_encryption
diff --git a/src/parquet/util/crypto.h b/src/parquet/util/crypto.h
deleted file mode 100644
index d3beb10..0000000
--- a/src/parquet/util/crypto.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// 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.
-
-#ifndef PARQUET_UTIL_CRYPTO_H
-#define PARQUET_UTIL_CRYPTO_H
-
-#include "parquet/properties.h"
-#include "parquet/types.h"
-
-using parquet::Encryption;
-using parquet::EncryptionProperties;
-
-namespace parquet_encryption {
-
-int Encrypt(Encryption::type alg_id, bool metadata, const uint8_t* plaintext,
-            int plaintext_len, uint8_t* key, int key_len, uint8_t* aad, int aad_len,
-            uint8_t* ciphertext);
-
-int Encrypt(std::shared_ptr<EncryptionProperties> encryption_props, bool metadata,
-            const uint8_t* plaintext, int plaintext_len, uint8_t* ciphertext);
-
-int Decrypt(Encryption::type alg_id, bool metadata, const uint8_t* ciphertext,
-            int ciphertext_len, uint8_t* key, int key_len, uint8_t* aad, int aad_len,
-            uint8_t* plaintext);
-
-int Decrypt(std::shared_ptr<EncryptionProperties> encryption_props, bool metadata,
-            const uint8_t* ciphertext, int ciphertext_len, uint8_t* plaintext);
-}  // namespace parquet_encryption
-
-#endif  // PARQUET_UTIL_CRYPTO_H
diff --git a/src/parquet/util/logging.h b/src/parquet/util/logging.h
deleted file mode 100644
index e2c7abb..0000000
--- a/src/parquet/util/logging.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// 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.
-
-#ifndef PARQUET_UTIL_LOGGING_H
-#define PARQUET_UTIL_LOGGING_H
-
-#include "arrow/util/logging.h"
-
-#endif  // PARQUET_UTIL_LOGGING_H
diff --git a/src/parquet/util/macros.h b/src/parquet/util/macros.h
deleted file mode 100644
index c28b2fa..0000000
--- a/src/parquet/util/macros.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// 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.
-
-#ifndef PARQUET_UTIL_MACROS_H
-#define PARQUET_UTIL_MACROS_H
-
-// Useful macros from elsewhere
-
-// From Google gutil
-#ifndef DISALLOW_COPY_AND_ASSIGN
-#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
-  TypeName(const TypeName&) = delete;      \
-  void operator=(const TypeName&) = delete
-#endif
-
-#if defined(__GNUC__)
-#define PARQUET_PREDICT_FALSE(x) (__builtin_expect(x, 0))
-#define PARQUET_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
-#define PARQUET_NORETURN __attribute__((noreturn))
-#define PARQUET_PREFETCH(addr) __builtin_prefetch(addr)
-#elif defined(_MSC_VER)
-#define PARQUET_NORETURN __declspec(noreturn)
-#define PARQUET_PREDICT_FALSE(x) x
-#define PARQUET_PREDICT_TRUE(x) x
-#define PARQUET_PREFETCH(addr)
-#else
-#define PARQUET_NORETURN
-#define PARQUET_PREDICT_FALSE(x) x
-#define PARQUET_PREDICT_TRUE(x) x
-#define PARQUET_PREFETCH(addr)
-#endif
-
-// ----------------------------------------------------------------------
-// From googletest
-
-// When you need to test the private or protected members of a class,
-// use the FRIEND_TEST macro to declare your tests as friends of the
-// class.  For example:
-//
-// class MyClass {
-//  private:
-//   void MyMethod();
-//   FRIEND_TEST(MyClassTest, MyMethod);
-// };
-//
-// class MyClassTest : public testing::Test {
-//   // ...
-// };
-//
-// TEST_F(MyClassTest, MyMethod) {
-//   // Can call MyClass::MyMethod() here.
-// }
-
-#define FRIEND_TEST(test_case_name, test_name) \
-  friend class test_case_name##_##test_name##_Test
-
-// clang-format off
-// [[deprecated]] is only available in C++14, use this for the time being
-// This macro takes an optional deprecation message
-#if __cplusplus <= 201103L
-# ifdef __GNUC__
-#  define PARQUET_DEPRECATED(...) __attribute__((deprecated(__VA_ARGS__)))
-# elif defined(_MSC_VER)
-#  define PARQUET_DEPRECATED(...) __declspec(deprecated(__VA_ARGS__))
-# else
-#  define PARQUET_DEPRECATED(...)
-# endif
-#else
-#  define PARQUET_DEPRECATED(...) [[deprecated(__VA_ARGS__)]]
-#endif
-
-#endif  // PARQUET_UTIL_MACROS_H
diff --git a/src/parquet/util/memory-test.cc b/src/parquet/util/memory-test.cc
deleted file mode 100644
index bfd685d..0000000
--- a/src/parquet/util/memory-test.cc
+++ /dev/null
@@ -1,362 +0,0 @@
-// 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.
-
-#include <cstdint>
-#include <cstdio>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include "parquet/exception.h"
-#include "parquet/util/memory.h"
-#include "parquet/util/test-common.h"
-
-using arrow::default_memory_pool;
-using arrow::MemoryPool;
-
-namespace parquet {
-
-class TestBuffer : public ::testing::Test {};
-
-// Utility class to call private functions on MemPool.
-class ChunkedAllocatorTest {
- public:
-  static bool CheckIntegrity(ChunkedAllocator* pool, bool current_chunk_empty) {
-    return pool->CheckIntegrity(current_chunk_empty);
-  }
-
-  static const int INITIAL_CHUNK_SIZE = ChunkedAllocator::INITIAL_CHUNK_SIZE;
-  static const int MAX_CHUNK_SIZE = ChunkedAllocator::MAX_CHUNK_SIZE;
-};
-
-const int ChunkedAllocatorTest::INITIAL_CHUNK_SIZE;
-const int ChunkedAllocatorTest::MAX_CHUNK_SIZE;
-
-TEST(ChunkedAllocatorTest, Basic) {
-  ChunkedAllocator p;
-  ChunkedAllocator p2;
-  ChunkedAllocator p3;
-
-  for (int iter = 0; iter < 2; ++iter) {
-    // allocate a total of 24K in 32-byte pieces (for which we only request 25 bytes)
-    for (int i = 0; i < 768; ++i) {
-      // pads to 32 bytes
-      p.Allocate(25);
-    }
-    // we handed back 24K
-    EXPECT_EQ(24 * 1024, p.total_allocated_bytes());
-    // .. and allocated 28K of chunks (4, 8, 16)
-    EXPECT_EQ(28 * 1024, p.GetTotalChunkSizes());
-
-    // we're passing on the first two chunks, containing 12K of data; we're left with
-    // one chunk of 16K containing 12K of data
-    p2.AcquireData(&p, true);
-    EXPECT_EQ(12 * 1024, p.total_allocated_bytes());
-    EXPECT_EQ(16 * 1024, p.GetTotalChunkSizes());
-
-    // we allocate 8K, for which there isn't enough room in the current chunk,
-    // so another one is allocated (32K)
-    p.Allocate(8 * 1024);
-    EXPECT_EQ((16 + 32) * 1024, p.GetTotalChunkSizes());
-
-    // we allocate 65K, which doesn't fit into the current chunk or the default
-    // size of the next allocated chunk (64K)
-    p.Allocate(65 * 1024);
-    EXPECT_EQ((12 + 8 + 65) * 1024, p.total_allocated_bytes());
-    if (iter == 0) {
-      EXPECT_EQ((12 + 8 + 65) * 1024, p.peak_allocated_bytes());
-    } else {
-      EXPECT_EQ((1 + 120 + 33) * 1024, p.peak_allocated_bytes());
-    }
-    EXPECT_EQ((16 + 32 + 65) * 1024, p.GetTotalChunkSizes());
-
-    // Clear() resets allocated data, but doesn't remove any chunks
-    p.Clear();
-    EXPECT_EQ(0, p.total_allocated_bytes());
-    if (iter == 0) {
-      EXPECT_EQ((12 + 8 + 65) * 1024, p.peak_allocated_bytes());
-    } else {
-      EXPECT_EQ((1 + 120 + 33) * 1024, p.peak_allocated_bytes());
-    }
-    EXPECT_EQ((16 + 32 + 65) * 1024, p.GetTotalChunkSizes());
-
-    // next allocation reuses existing chunks
-    p.Allocate(1024);
-    EXPECT_EQ(1024, p.total_allocated_bytes());
-    if (iter == 0) {
-      EXPECT_EQ((12 + 8 + 65) * 1024, p.peak_allocated_bytes());
-    } else {
-      EXPECT_EQ((1 + 120 + 33) * 1024, p.peak_allocated_bytes());
-    }
-    EXPECT_EQ((16 + 32 + 65) * 1024, p.GetTotalChunkSizes());
-
-    // ... unless it doesn't fit into any available chunk
-    p.Allocate(120 * 1024);
-    EXPECT_EQ((1 + 120) * 1024, p.total_allocated_bytes());
-    if (iter == 0) {
-      EXPECT_EQ((1 + 120) * 1024, p.peak_allocated_bytes());
-    } else {
-      EXPECT_EQ((1 + 120 + 33) * 1024, p.peak_allocated_bytes());
-    }
-    EXPECT_EQ((130 + 16 + 32 + 65) * 1024, p.GetTotalChunkSizes());
-
-    // ... Try another chunk that fits into an existing chunk
-    p.Allocate(33 * 1024);
-    EXPECT_EQ((1 + 120 + 33) * 1024, p.total_allocated_bytes());
-    EXPECT_EQ((130 + 16 + 32 + 65) * 1024, p.GetTotalChunkSizes());
-
-    // we're releasing 3 chunks, which get added to p2
-    p2.AcquireData(&p, false);
-    EXPECT_EQ(0, p.total_allocated_bytes());
-    EXPECT_EQ((1 + 120 + 33) * 1024, p.peak_allocated_bytes());
-    EXPECT_EQ(0, p.GetTotalChunkSizes());
-
-    p3.AcquireData(&p2, true);  // we're keeping the 65k chunk
-    EXPECT_EQ(33 * 1024, p2.total_allocated_bytes());
-    EXPECT_EQ(65 * 1024, p2.GetTotalChunkSizes());
-
-    p.FreeAll();
-    p2.FreeAll();
-    p3.FreeAll();
-  }
-}
-
-// Test that we can keep an allocated chunk and a free chunk.
-// This case verifies that when chunks are acquired by another memory pool the
-// remaining chunks are consistent if there were more than one used chunk and some
-// free chunks.
-TEST(ChunkedAllocatorTest, Keep) {
-  ChunkedAllocator p;
-  p.Allocate(4 * 1024);
-  p.Allocate(8 * 1024);
-  p.Allocate(16 * 1024);
-  EXPECT_EQ((4 + 8 + 16) * 1024, p.total_allocated_bytes());
-  EXPECT_EQ((4 + 8 + 16) * 1024, p.GetTotalChunkSizes());
-  p.Clear();
-  EXPECT_EQ(0, p.total_allocated_bytes());
-  EXPECT_EQ((4 + 8 + 16) * 1024, p.GetTotalChunkSizes());
-  p.Allocate(1 * 1024);
-  p.Allocate(4 * 1024);
-  EXPECT_EQ((1 + 4) * 1024, p.total_allocated_bytes());
-  EXPECT_EQ((4 + 8 + 16) * 1024, p.GetTotalChunkSizes());
-
-  ChunkedAllocator p2;
-  p2.AcquireData(&p, true);
-  EXPECT_EQ(4 * 1024, p.total_allocated_bytes());
-  EXPECT_EQ((8 + 16) * 1024, p.GetTotalChunkSizes());
-  EXPECT_EQ(1 * 1024, p2.total_allocated_bytes());
-  EXPECT_EQ(4 * 1024, p2.GetTotalChunkSizes());
-
-  p.FreeAll();
-  p2.FreeAll();
-}
-
-// Tests that we can return partial allocations.
-TEST(ChunkedAllocatorTest, ReturnPartial) {
-  ChunkedAllocator p;
-  uint8_t* ptr = p.Allocate(1024);
-  EXPECT_EQ(1024, p.total_allocated_bytes());
-  memset(ptr, 0, 1024);
-  p.ReturnPartialAllocation(1024);
-
-  uint8_t* ptr2 = p.Allocate(1024);
-  EXPECT_EQ(1024, p.total_allocated_bytes());
-  EXPECT_TRUE(ptr == ptr2);
-  p.ReturnPartialAllocation(1016);
-
-  ptr2 = p.Allocate(1016);
-  EXPECT_EQ(1024, p.total_allocated_bytes());
-  EXPECT_TRUE(ptr2 == ptr + 8);
-  p.ReturnPartialAllocation(512);
-  memset(ptr2, 1, 1016 - 512);
-
-  uint8_t* ptr3 = p.Allocate(512);
-  EXPECT_EQ(1024, p.total_allocated_bytes());
-  EXPECT_TRUE(ptr3 == ptr + 512);
-  memset(ptr3, 2, 512);
-
-  for (int i = 0; i < 8; ++i) {
-    EXPECT_EQ(0, ptr[i]);
-  }
-  for (int i = 8; i < 512; ++i) {
-    EXPECT_EQ(1, ptr[i]);
-  }
-  for (int i = 512; i < 1024; ++i) {
-    EXPECT_EQ(2, ptr[i]);
-  }
-
-  p.FreeAll();
-}
-
-// Test that the ChunkedAllocator overhead is bounded when we make allocations of
-// INITIAL_CHUNK_SIZE.
-TEST(ChunkedAllocatorTest, MemoryOverhead) {
-  ChunkedAllocator p;
-  const int alloc_size = ChunkedAllocatorTest::INITIAL_CHUNK_SIZE;
-  const int num_allocs = 1000;
-  int64_t total_allocated = 0;
-
-  for (int i = 0; i < num_allocs; ++i) {
-    uint8_t* mem = p.Allocate(alloc_size);
-    ASSERT_TRUE(mem != nullptr);
-    total_allocated += alloc_size;
-
-    int64_t wasted_memory = p.GetTotalChunkSizes() - total_allocated;
-    // The initial chunk fits evenly into MAX_CHUNK_SIZE, so should have at most
-    // one empty chunk at the end.
-    EXPECT_LE(wasted_memory, ChunkedAllocatorTest::MAX_CHUNK_SIZE);
-    // The chunk doubling algorithm should not allocate chunks larger than the total
-    // amount of memory already allocated.
-    EXPECT_LE(wasted_memory, total_allocated);
-  }
-
-  p.FreeAll();
-}
-
-// Test that the ChunkedAllocator overhead is bounded when we make alternating
-// large and small allocations.
-TEST(ChunkedAllocatorTest, FragmentationOverhead) {
-  ChunkedAllocator p;
-  const int num_allocs = 100;
-  int64_t total_allocated = 0;
-
-  for (int i = 0; i < num_allocs; ++i) {
-    int alloc_size = i % 2 == 0 ? 1 : ChunkedAllocatorTest::MAX_CHUNK_SIZE;
-    uint8_t* mem = p.Allocate(alloc_size);
-    ASSERT_TRUE(mem != nullptr);
-    total_allocated += alloc_size;
-
-    int64_t wasted_memory = p.GetTotalChunkSizes() - total_allocated;
-    // Fragmentation should not waste more than half of each completed chunk.
-    EXPECT_LE(wasted_memory, total_allocated + ChunkedAllocatorTest::MAX_CHUNK_SIZE);
-  }
-
-  p.FreeAll();
-}
-
-TEST(TestBufferedInputStream, Basics) {
-  int64_t source_size = 256;
-  int64_t stream_offset = 10;
-  int64_t stream_size = source_size - stream_offset;
-  int64_t chunk_size = 50;
-  std::shared_ptr<ResizableBuffer> buf =
-      AllocateBuffer(default_memory_pool(), source_size);
-  ASSERT_EQ(source_size, buf->size());
-  for (int i = 0; i < source_size; i++) {
-    buf->mutable_data()[i] = static_cast<uint8_t>(i);
-  }
-
-  auto wrapper =
-      std::make_shared<ArrowInputFile>(std::make_shared<::arrow::io::BufferReader>(buf));
-
-  std::unique_ptr<BufferedInputStream> stream(new BufferedInputStream(
-      default_memory_pool(), chunk_size, wrapper.get(), stream_offset, stream_size));
-
-  const uint8_t* output;
-  int64_t bytes_read;
-
-  // source is at offset 10
-  output = stream->Peek(10, &bytes_read);
-  ASSERT_EQ(10, bytes_read);
-  for (int i = 0; i < 10; i++) {
-    ASSERT_EQ(10 + i, output[i]) << i;
-  }
-  output = stream->Read(10, &bytes_read);
-  ASSERT_EQ(10, bytes_read);
-  for (int i = 0; i < 10; i++) {
-    ASSERT_EQ(10 + i, output[i]) << i;
-  }
-  output = stream->Read(10, &bytes_read);
-  ASSERT_EQ(10, bytes_read);
-  for (int i = 0; i < 10; i++) {
-    ASSERT_EQ(20 + i, output[i]) << i;
-  }
-  stream->Advance(5);
-  stream->Advance(5);
-  // source is at offset 40
-  // read across buffer boundary. buffer size is 50
-  output = stream->Read(20, &bytes_read);
-  ASSERT_EQ(20, bytes_read);
-  for (int i = 0; i < 20; i++) {
-    ASSERT_EQ(40 + i, output[i]) << i;
-  }
-  // read more than original chunk_size
-  output = stream->Read(60, &bytes_read);
-  ASSERT_EQ(60, bytes_read);
-  for (int i = 0; i < 60; i++) {
-    ASSERT_EQ(60 + i, output[i]) << i;
-  }
-
-  stream->Advance(120);
-  // source is at offset 240
-  // read outside of source boundary. source size is 256
-  output = stream->Read(30, &bytes_read);
-  ASSERT_EQ(16, bytes_read);
-  for (int i = 0; i < 16; i++) {
-    ASSERT_EQ(240 + i, output[i]) << i;
-  }
-}
-
-TEST(TestArrowInputFile, ReadAt) {
-  std::string data = "this is the data";
-  auto data_buffer = reinterpret_cast<const uint8_t*>(data.c_str());
-
-  auto file = std::make_shared<::arrow::io::BufferReader>(data_buffer, data.size());
-  auto source = std::make_shared<ArrowInputFile>(file);
-
-  ASSERT_EQ(0, source->Tell());
-
-  uint8_t buffer[50];
-
-  ASSERT_NO_THROW(source->ReadAt(0, 4, buffer));
-  ASSERT_EQ(0, std::memcmp(buffer, "this", 4));
-
-  // Note: it's undefined (and possibly platform-dependent) whether ArrowInputFile
-  // updates the file position after ReadAt().
-}
-
-TEST(TestArrowInputFile, Read) {
-  std::string data = "this is the data";
-  auto data_buffer = reinterpret_cast<const uint8_t*>(data.c_str());
-
-  auto file = std::make_shared<::arrow::io::BufferReader>(data_buffer, data.size());
-  auto source = std::make_shared<ArrowInputFile>(file);
-
-  ASSERT_EQ(0, source->Tell());
-
-  std::shared_ptr<Buffer> pq_buffer, expected_buffer;
-
-  ASSERT_NO_THROW(pq_buffer = source->Read(4));
-  expected_buffer = std::make_shared<Buffer>(data_buffer, 4);
-  ASSERT_TRUE(expected_buffer->Equals(*pq_buffer.get()));
-
-  ASSERT_NO_THROW(pq_buffer = source->Read(7));
-  expected_buffer = std::make_shared<Buffer>(data_buffer + 4, 7);
-  ASSERT_TRUE(expected_buffer->Equals(*pq_buffer.get()));
-
-  ASSERT_EQ(11, source->Tell());
-
-  ASSERT_NO_THROW(pq_buffer = source->Read(8));
-  expected_buffer = std::make_shared<Buffer>(data_buffer + 11, 5);
-  ASSERT_TRUE(expected_buffer->Equals(*pq_buffer.get()));
-
-  ASSERT_EQ(16, source->Tell());
-}
-
-}  // namespace parquet
diff --git a/src/parquet/util/memory.cc b/src/parquet/util/memory.cc
deleted file mode 100644
index d9caf6e..0000000
--- a/src/parquet/util/memory.cc
+++ /dev/null
@@ -1,502 +0,0 @@
-// 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.
-
-#include "parquet/util/memory.h"
-
-#include <algorithm>
-#include <cstdint>
-#include <cstdio>
-#include <string>
-#include <utility>
-
-#include "arrow/status.h"
-#include "arrow/util/bit-util.h"
-
-#include "parquet/exception.h"
-#include "parquet/types.h"
-#include "parquet/util/logging.h"
-
-using arrow::MemoryPool;
-
-namespace parquet {
-
-template <class T>
-Vector<T>::Vector(int64_t size, MemoryPool* pool)
-    : buffer_(AllocateBuffer(pool, size * sizeof(T))), size_(size), capacity_(size) {
-  if (size > 0) {
-    data_ = reinterpret_cast<T*>(buffer_->mutable_data());
-  } else {
-    data_ = nullptr;
-  }
-}
-
-template <class T>
-void Vector<T>::Reserve(int64_t new_capacity) {
-  if (new_capacity > capacity_) {
-    PARQUET_THROW_NOT_OK(buffer_->Resize(new_capacity * sizeof(T)));
-    data_ = reinterpret_cast<T*>(buffer_->mutable_data());
-    capacity_ = new_capacity;
-  }
-}
-
-template <class T>
-void Vector<T>::Resize(int64_t new_size) {
-  Reserve(new_size);
-  size_ = new_size;
-}
-
-template <class T>
-void Vector<T>::Assign(int64_t size, const T val) {
-  Resize(size);
-  for (int64_t i = 0; i < size_; i++) {
-    data_[i] = val;
-  }
-}
-
-template <class T>
-void Vector<T>::Swap(Vector<T>& v) {
-  buffer_.swap(v.buffer_);
-  std::swap(size_, v.size_);
-  std::swap(capacity_, v.capacity_);
-  std::swap(data_, v.data_);
-}
-
-template class Vector<int32_t>;
-template class Vector<int64_t>;
-template class Vector<bool>;
-template class Vector<float>;
-template class Vector<double>;
-template class Vector<Int96>;
-template class Vector<ByteArray>;
-template class Vector<FixedLenByteArray>;
-
-const int ChunkedAllocator::INITIAL_CHUNK_SIZE;
-const int ChunkedAllocator::MAX_CHUNK_SIZE;
-
-ChunkedAllocator::ChunkedAllocator(MemoryPool* pool)
-    : current_chunk_idx_(-1),
-      next_chunk_size_(INITIAL_CHUNK_SIZE),
-      total_allocated_bytes_(0),
-      peak_allocated_bytes_(0),
-      total_reserved_bytes_(0),
-      pool_(pool) {}
-
-ChunkedAllocator::ChunkInfo::ChunkInfo(int64_t size, uint8_t* buf)
-    : data(buf), size(size), allocated_bytes(0) {}
-
-ChunkedAllocator::~ChunkedAllocator() {
-  int64_t total_bytes_released = 0;
-  for (size_t i = 0; i < chunks_.size(); ++i) {
-    total_bytes_released += chunks_[i].size;
-    pool_->Free(chunks_[i].data, chunks_[i].size);
-  }
-
-  DCHECK(chunks_.empty()) << "Must call FreeAll() or AcquireData() for this pool";
-}
-
-void ChunkedAllocator::ReturnPartialAllocation(int byte_size) {
-  DCHECK_GE(byte_size, 0);
-  DCHECK(current_chunk_idx_ != -1);
-  ChunkInfo& info = chunks_[current_chunk_idx_];
-  DCHECK_GE(info.allocated_bytes, byte_size);
-  info.allocated_bytes -= byte_size;
-  total_allocated_bytes_ -= byte_size;
-}
-
-template <bool CHECK_LIMIT_FIRST>
-uint8_t* ChunkedAllocator::Allocate(int size) {
-  if (size == 0) {
-    return nullptr;
-  }
-
-  int64_t num_bytes = ::arrow::BitUtil::RoundUp(size, 8);
-  if (current_chunk_idx_ == -1 ||
-      num_bytes + chunks_[current_chunk_idx_].allocated_bytes >
-          chunks_[current_chunk_idx_].size) {
-    // If we couldn't allocate a new chunk, return nullptr.
-    if (ARROW_PREDICT_FALSE(!FindChunk(num_bytes))) {
-      return nullptr;
-    }
-  }
-  ChunkInfo& info = chunks_[current_chunk_idx_];
-  uint8_t* result = info.data + info.allocated_bytes;
-  DCHECK_LE(info.allocated_bytes + num_bytes, info.size);
-  info.allocated_bytes += num_bytes;
-  total_allocated_bytes_ += num_bytes;
-  DCHECK_LE(current_chunk_idx_, static_cast<int>(chunks_.size()) - 1);
-  peak_allocated_bytes_ = std::max(total_allocated_bytes_, peak_allocated_bytes_);
-  return result;
-}
-
-uint8_t* ChunkedAllocator::Allocate(int size) { return Allocate<false>(size); }
-
-void ChunkedAllocator::Clear() {
-  current_chunk_idx_ = -1;
-  for (auto chunk = chunks_.begin(); chunk != chunks_.end(); ++chunk) {
-    chunk->allocated_bytes = 0;
-  }
-  total_allocated_bytes_ = 0;
-  DCHECK(CheckIntegrity(false));
-}
-
-void ChunkedAllocator::FreeAll() {
-  int64_t total_bytes_released = 0;
-  for (size_t i = 0; i < chunks_.size(); ++i) {
-    total_bytes_released += chunks_[i].size;
-    pool_->Free(chunks_[i].data, chunks_[i].size);
-  }
-  chunks_.clear();
-  next_chunk_size_ = INITIAL_CHUNK_SIZE;
-  current_chunk_idx_ = -1;
-  total_allocated_bytes_ = 0;
-  total_reserved_bytes_ = 0;
-}
-
-bool ChunkedAllocator::FindChunk(int64_t min_size) {
-  // Try to allocate from a free chunk. The first free chunk, if any, will be immediately
-  // after the current chunk.
-  int first_free_idx = current_chunk_idx_ + 1;
-  // (cast size() to signed int in order to avoid everything else being cast to
-  // unsigned long, in particular -1)
-  while (++current_chunk_idx_ < static_cast<int>(chunks_.size())) {
-    // we found a free chunk
-    DCHECK_EQ(chunks_[current_chunk_idx_].allocated_bytes, 0);
-
-    if (chunks_[current_chunk_idx_].size >= min_size) {
-      // This chunk is big enough.  Move it before the other free chunks.
-      if (current_chunk_idx_ != first_free_idx) {
-        std::swap(chunks_[current_chunk_idx_], chunks_[first_free_idx]);
-        current_chunk_idx_ = first_free_idx;
-      }
-      break;
-    }
-  }
-
-  if (current_chunk_idx_ == static_cast<int>(chunks_.size())) {
-    // need to allocate new chunk.
-    int64_t chunk_size;
-    DCHECK_GE(next_chunk_size_, INITIAL_CHUNK_SIZE);
-    DCHECK_LE(next_chunk_size_, MAX_CHUNK_SIZE);
-
-    chunk_size = std::max<int64_t>(min_size, next_chunk_size_);
-
-    // Allocate a new chunk. Return early if malloc fails.
-    uint8_t* buf = nullptr;
-    PARQUET_THROW_NOT_OK(pool_->Allocate(chunk_size, &buf));
-    if (ARROW_PREDICT_FALSE(buf == nullptr)) {
-      DCHECK_EQ(current_chunk_idx_, static_cast<int>(chunks_.size()));
-      current_chunk_idx_ = static_cast<int>(chunks_.size()) - 1;
-      return false;
-    }
-
-    // If there are no free chunks put it at the end, otherwise before the first free.
-    if (first_free_idx == static_cast<int>(chunks_.size())) {
-      chunks_.push_back(ChunkInfo(chunk_size, buf));
-    } else {
-      current_chunk_idx_ = first_free_idx;
-      auto insert_chunk = chunks_.begin() + current_chunk_idx_;
-      chunks_.insert(insert_chunk, ChunkInfo(chunk_size, buf));
-    }
-    total_reserved_bytes_ += chunk_size;
-    // Don't increment the chunk size until the allocation succeeds: if an attempted
-    // large allocation fails we don't want to increase the chunk size further.
-    next_chunk_size_ =
-        static_cast<int>(std::min<int64_t>(chunk_size * 2, MAX_CHUNK_SIZE));
-  }
-
-  DCHECK_LT(current_chunk_idx_, static_cast<int>(chunks_.size()));
-  DCHECK(CheckIntegrity(true));
-  return true;
-}
-
-void ChunkedAllocator::AcquireData(ChunkedAllocator* src, bool keep_current) {
-  DCHECK(src->CheckIntegrity(false));
-  int num_acquired_chunks;
-  if (keep_current) {
-    num_acquired_chunks = src->current_chunk_idx_;
-  } else if (src->GetFreeOffset() == 0) {
-    // nothing in the last chunk
-    num_acquired_chunks = src->current_chunk_idx_;
-  } else {
-    num_acquired_chunks = src->current_chunk_idx_ + 1;
-  }
-
-  if (num_acquired_chunks <= 0) {
-    if (!keep_current) src->FreeAll();
-    return;
-  }
-
-  auto end_chunk = src->chunks_.begin() + num_acquired_chunks;
-  int64_t total_transfered_bytes = 0;
-  for (auto i = src->chunks_.begin(); i != end_chunk; ++i) {
-    total_transfered_bytes += i->size;
-  }
-  src->total_reserved_bytes_ -= total_transfered_bytes;
-  total_reserved_bytes_ += total_transfered_bytes;
-
-  // insert new chunks after current_chunk_idx_
-  auto insert_chunk = chunks_.begin() + (current_chunk_idx_ + 1);
-  chunks_.insert(insert_chunk, src->chunks_.begin(), end_chunk);
-  src->chunks_.erase(src->chunks_.begin(), end_chunk);
-  current_chunk_idx_ += num_acquired_chunks;
-
-  if (keep_current) {
-    src->current_chunk_idx_ = 0;
-    DCHECK(src->chunks_.size() == 1 || src->chunks_[1].allocated_bytes == 0);
-    total_allocated_bytes_ += src->total_allocated_bytes_ - src->GetFreeOffset();
-    src->total_allocated_bytes_ = src->GetFreeOffset();
-  } else {
-    src->current_chunk_idx_ = -1;
-    total_allocated_bytes_ += src->total_allocated_bytes_;
-    src->total_allocated_bytes_ = 0;
-  }
-  peak_allocated_bytes_ = std::max(total_allocated_bytes_, peak_allocated_bytes_);
-
-  if (!keep_current) src->FreeAll();
-  DCHECK(CheckIntegrity(false));
-}
-
-std::string ChunkedAllocator::DebugString() {
-  std::stringstream out;
-  char str[16];
-  out << "ChunkedAllocator(#chunks=" << chunks_.size() << " [";
-  for (size_t i = 0; i < chunks_.size(); ++i) {
-    sprintf(str, "0x%zx=", reinterpret_cast<size_t>(chunks_[i].data));  // NOLINT
-    out << (i > 0 ? " " : "") << str << chunks_[i].size << "/"
-        << chunks_[i].allocated_bytes;
-  }
-  out << "] current_chunk=" << current_chunk_idx_
-      << " total_sizes=" << GetTotalChunkSizes()
-      << " total_alloc=" << total_allocated_bytes_ << ")";
-  return out.str();
-}
-
-int64_t ChunkedAllocator::GetTotalChunkSizes() const {
-  int64_t result = 0;
-  for (size_t i = 0; i < chunks_.size(); ++i) {
-    result += chunks_[i].size;
-  }
-  return result;
-}
-
-bool ChunkedAllocator::CheckIntegrity(bool current_chunk_empty) {
-  // check that current_chunk_idx_ points to the last chunk with allocated data
-  DCHECK_LT(current_chunk_idx_, static_cast<int>(chunks_.size()));
-  int64_t total_allocated = 0;
-  for (int i = 0; i < static_cast<int>(chunks_.size()); ++i) {
-    DCHECK_GT(chunks_[i].size, 0);
-    if (i < current_chunk_idx_) {
-      DCHECK_GT(chunks_[i].allocated_bytes, 0);
-    } else if (i == current_chunk_idx_) {
-      if (current_chunk_empty) {
-        DCHECK_EQ(chunks_[i].allocated_bytes, 0);
-      } else {
-        DCHECK_GT(chunks_[i].allocated_bytes, 0);
-      }
-    } else {
-      DCHECK_EQ(chunks_[i].allocated_bytes, 0);
-    }
-    total_allocated += chunks_[i].allocated_bytes;
-  }
-  DCHECK_EQ(total_allocated, total_allocated_bytes_);
-  return true;
-}
-
-// ----------------------------------------------------------------------
-// Arrow IO wrappers
-
-void ArrowFileMethods::Close() {
-  // Closing the file is the responsibility of the owner of the handle
-  return;
-}
-
-// Return the current position in the output stream relative to the start
-int64_t ArrowFileMethods::Tell() {
-  int64_t position = 0;
-  PARQUET_THROW_NOT_OK(file_interface()->Tell(&position));
-  return position;
-}
-
-ArrowInputFile::ArrowInputFile(
-    const std::shared_ptr<::arrow::io::ReadableFileInterface>& file)
-    : file_(file) {}
-
-::arrow::io::FileInterface* ArrowInputFile::file_interface() { return file_.get(); }
-
-int64_t ArrowInputFile::Size() const {
-  int64_t size;
-  PARQUET_THROW_NOT_OK(file_->GetSize(&size));
-  return size;
-}
-
-// Returns bytes read
-int64_t ArrowInputFile::Read(int64_t nbytes, uint8_t* out) {
-  int64_t bytes_read = 0;
-  PARQUET_THROW_NOT_OK(file_->Read(nbytes, &bytes_read, out));
-  return bytes_read;
-}
-
-std::shared_ptr<Buffer> ArrowInputFile::Read(int64_t nbytes) {
-  std::shared_ptr<Buffer> out;
-  PARQUET_THROW_NOT_OK(file_->Read(nbytes, &out));
-  return out;
-}
-
-std::shared_ptr<Buffer> ArrowInputFile::ReadAt(int64_t position, int64_t nbytes) {
-  std::shared_ptr<Buffer> out;
-  PARQUET_THROW_NOT_OK(file_->ReadAt(position, nbytes, &out));
-  return out;
-}
-
-int64_t ArrowInputFile::ReadAt(int64_t position, int64_t nbytes, uint8_t* out) {
-  int64_t bytes_read = 0;
-  PARQUET_THROW_NOT_OK(file_->ReadAt(position, nbytes, &bytes_read, out));
-  return bytes_read;
-}
-
-ArrowOutputStream::ArrowOutputStream(
-    const std::shared_ptr<::arrow::io::OutputStream> file)
-    : file_(file) {}
-
-::arrow::io::FileInterface* ArrowOutputStream::file_interface() { return file_.get(); }
-
-// Copy bytes into the output stream
-void ArrowOutputStream::Write(const uint8_t* data, int64_t length) {
-  PARQUET_THROW_NOT_OK(file_->Write(data, length));
-}
-
-// ----------------------------------------------------------------------
-// InMemoryInputStream
-
-InMemoryInputStream::InMemoryInputStream(const std::shared_ptr<Buffer>& buffer)
-    : buffer_(buffer), offset_(0) {
-  len_ = buffer_->size();
-}
-
-InMemoryInputStream::InMemoryInputStream(RandomAccessSource* source, int64_t start,
-                                         int64_t num_bytes)
-    : offset_(0) {
-  buffer_ = source->ReadAt(start, num_bytes);
-  if (buffer_->size() < num_bytes) {
-    throw ParquetException("Unable to read column chunk data");
-  }
-  len_ = buffer_->size();
-}
-
-const uint8_t* InMemoryInputStream::Peek(int64_t num_to_peek, int64_t* num_bytes) {
-  *num_bytes = std::min(static_cast<int64_t>(num_to_peek), len_ - offset_);
-  return buffer_->data() + offset_;
-}
-
-const uint8_t* InMemoryInputStream::Read(int64_t num_to_read, int64_t* num_bytes) {
-  const uint8_t* result = Peek(num_to_read, num_bytes);
-  offset_ += *num_bytes;
-  return result;
-}
-
-void InMemoryInputStream::Advance(int64_t num_bytes) { offset_ += num_bytes; }
-
-// ----------------------------------------------------------------------
-// In-memory output stream
-
-InMemoryOutputStream::InMemoryOutputStream(MemoryPool* pool, int64_t initial_capacity)
-    : size_(0), capacity_(initial_capacity) {
-  if (initial_capacity == 0) {
-    initial_capacity = kInMemoryDefaultCapacity;
-  }
-  buffer_ = AllocateBuffer(pool, initial_capacity);
-}
-
-InMemoryOutputStream::~InMemoryOutputStream() {}
-
-uint8_t* InMemoryOutputStream::Head() { return buffer_->mutable_data() + size_; }
-
-void InMemoryOutputStream::Write(const uint8_t* data, int64_t length) {
-  if (size_ + length > capacity_) {
-    int64_t new_capacity = capacity_ * 2;
-    while (new_capacity < size_ + length) {
-      new_capacity *= 2;
-    }
-    PARQUET_THROW_NOT_OK(buffer_->Resize(new_capacity));
-    capacity_ = new_capacity;
-  }
-  memcpy(Head(), data, length);
-  size_ += length;
-}
-
-int64_t InMemoryOutputStream::Tell() { return size_; }
-
-std::shared_ptr<Buffer> InMemoryOutputStream::GetBuffer() {
-  PARQUET_THROW_NOT_OK(buffer_->Resize(size_));
-  std::shared_ptr<Buffer> result = buffer_;
-  buffer_ = nullptr;
-  return result;
-}
-
-// ----------------------------------------------------------------------
-// BufferedInputStream
-
-BufferedInputStream::BufferedInputStream(MemoryPool* pool, int64_t buffer_size,
-                                         RandomAccessSource* source, int64_t start,
-                                         int64_t num_bytes)
-    : source_(source), stream_offset_(start), stream_end_(start + num_bytes) {
-  buffer_ = AllocateBuffer(pool, buffer_size);
-  buffer_size_ = buffer_->size();
-  // Required to force a lazy read
-  buffer_offset_ = buffer_size_;
-}
-
-const uint8_t* BufferedInputStream::Peek(int64_t num_to_peek, int64_t* num_bytes) {
-  *num_bytes = std::min(num_to_peek, stream_end_ - stream_offset_);
-  // increase the buffer size if needed
-  if (*num_bytes > buffer_size_) {
-    PARQUET_THROW_NOT_OK(buffer_->Resize(*num_bytes));
-    buffer_size_ = buffer_->size();
-    DCHECK(buffer_size_ >= *num_bytes);
-  }
-  // Read more data when buffer has insufficient left or when resized
-  if (*num_bytes > (buffer_size_ - buffer_offset_)) {
-    buffer_size_ = std::min(buffer_size_, stream_end_ - stream_offset_);
-    int64_t bytes_read =
-        source_->ReadAt(stream_offset_, buffer_size_, buffer_->mutable_data());
-    if (bytes_read < *num_bytes) {
-      throw ParquetException("Failed reading column data from source");
-    }
-    buffer_offset_ = 0;
-  }
-  return buffer_->data() + buffer_offset_;
-}
-
-const uint8_t* BufferedInputStream::Read(int64_t num_to_read, int64_t* num_bytes) {
-  const uint8_t* result = Peek(num_to_read, num_bytes);
-  stream_offset_ += *num_bytes;
-  buffer_offset_ += *num_bytes;
-  return result;
-}
-
-void BufferedInputStream::Advance(int64_t num_bytes) {
-  stream_offset_ += num_bytes;
-  buffer_offset_ += num_bytes;
-}
-
-std::shared_ptr<ResizableBuffer> AllocateBuffer(MemoryPool* pool, int64_t size) {
-  std::shared_ptr<ResizableBuffer> result;
-  PARQUET_THROW_NOT_OK(arrow::AllocateResizableBuffer(pool, size, &result));
-  return result;
-}
-
-}  // namespace parquet
diff --git a/src/parquet/util/memory.h b/src/parquet/util/memory.h
deleted file mode 100644
index 088f86f..0000000
--- a/src/parquet/util/memory.h
+++ /dev/null
@@ -1,445 +0,0 @@
-// 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.
-
-#ifndef PARQUET_UTIL_MEMORY_H
-#define PARQUET_UTIL_MEMORY_H
-
-#include <atomic>
-#include <cstdint>
-#include <cstdlib>
-#include <cstring>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "arrow/buffer.h"
-#include "arrow/io/interfaces.h"
-#include "arrow/io/memory.h"
-#include "arrow/memory_pool.h"
-#include "arrow/status.h"
-#include "arrow/util/compression.h"
-
-#include "parquet/exception.h"
-#include "parquet/types.h"
-#include "parquet/util/macros.h"
-#include "parquet/util/visibility.h"
-
-namespace parquet {
-
-static inline std::unique_ptr<::arrow::Codec> GetCodecFromArrow(Compression::type codec) {
-  std::unique_ptr<::arrow::Codec> result;
-  switch (codec) {
-    case Compression::UNCOMPRESSED:
-      break;
-    case Compression::SNAPPY:
-      PARQUET_THROW_NOT_OK(::arrow::Codec::Create(::arrow::Compression::SNAPPY, &result));
-      break;
-    case Compression::GZIP:
-      PARQUET_THROW_NOT_OK(::arrow::Codec::Create(::arrow::Compression::GZIP, &result));
-      break;
-    case Compression::LZO:
-      PARQUET_THROW_NOT_OK(::arrow::Codec::Create(::arrow::Compression::LZO, &result));
-      break;
-    case Compression::BROTLI:
-      PARQUET_THROW_NOT_OK(::arrow::Codec::Create(::arrow::Compression::BROTLI, &result));
-      break;
-    case Compression::LZ4:
-      PARQUET_THROW_NOT_OK(::arrow::Codec::Create(::arrow::Compression::LZ4, &result));
-      break;
-    case Compression::ZSTD:
-      PARQUET_THROW_NOT_OK(::arrow::Codec::Create(::arrow::Compression::ZSTD, &result));
-      break;
-    default:
-      break;
-  }
-  return result;
-}
-
-static constexpr int64_t kInMemoryDefaultCapacity = 1024;
-
-using Buffer = ::arrow::Buffer;
-using MutableBuffer = ::arrow::MutableBuffer;
-using ResizableBuffer = ::arrow::ResizableBuffer;
-using ResizableBuffer = ::arrow::ResizableBuffer;
-
-template <class T>
-class PARQUET_EXPORT Vector {
- public:
-  explicit Vector(int64_t size, ::arrow::MemoryPool* pool);
-  void Resize(int64_t new_size);
-  void Reserve(int64_t new_capacity);
-  void Assign(int64_t size, const T val);
-  void Swap(Vector<T>& v);
-  inline T& operator[](int64_t i) const { return data_[i]; }
-
-  const T* data() const { return data_; }
-
- private:
-  std::shared_ptr<ResizableBuffer> buffer_;
-  int64_t size_;
-  int64_t capacity_;
-  T* data_;
-
-  DISALLOW_COPY_AND_ASSIGN(Vector);
-};
-
-/// A ChunkedAllocator maintains a list of memory chunks from which it
-/// allocates memory in response to Allocate() calls; Chunks stay around for
-/// the lifetime of the allocator or until they are passed on to another
-/// allocator.
-//
-/// An Allocate() call will attempt to allocate memory from the chunk that was most
-/// recently added; if that chunk doesn't have enough memory to
-/// satisfy the allocation request, the free chunks are searched for one that is
-/// big enough otherwise a new chunk is added to the list.
-/// The current_chunk_idx_ always points to the last chunk with allocated memory.
-/// In order to keep allocation overhead low, chunk sizes double with each new one
-/// added, until they hit a maximum size.
-//
-///     Example:
-///     ChunkedAllocator* p = new ChunkedAllocator();
-///     for (int i = 0; i < 1024; ++i) {
-/// returns 8-byte aligned memory (effectively 24 bytes):
-///       .. = p->Allocate(17);
-///     }
-/// at this point, 17K have been handed out in response to Allocate() calls and
-/// 28K of chunks have been allocated (chunk sizes: 4K, 8K, 16K)
-/// We track total and peak allocated bytes. At this point they would be the same:
-/// 28k bytes.  A call to Clear will return the allocated memory so
-/// total_allocate_bytes_
-/// becomes 0 while peak_allocate_bytes_ remains at 28k.
-///     p->Clear();
-/// the entire 1st chunk is returned:
-///     .. = p->Allocate(4 * 1024);
-/// 4K of the 2nd chunk are returned:
-///     .. = p->Allocate(4 * 1024);
-/// a new 20K chunk is created
-///     .. = p->Allocate(20 * 1024);
-//
-///      ChunkedAllocator* p2 = new ChunkedAllocator();
-/// the new ChunkedAllocator receives all chunks containing data from p
-///      p2->AcquireData(p, false);
-/// At this point p.total_allocated_bytes_ would be 0 while p.peak_allocated_bytes_
-/// remains unchanged.
-/// The one remaining (empty) chunk is released:
-///    delete p;
-
-class PARQUET_EXPORT ChunkedAllocator {
- public:
-  explicit ChunkedAllocator(::arrow::MemoryPool* pool = ::arrow::default_memory_pool());
-
-  /// Frees all chunks of memory and subtracts the total allocated bytes
-  /// from the registered limits.
-  ~ChunkedAllocator();
-
-  /// Allocates 8-byte aligned section of memory of 'size' bytes at the end
-  /// of the the current chunk. Creates a new chunk if there aren't any chunks
-  /// with enough capacity.
-  uint8_t* Allocate(int size);
-
-  /// Returns 'byte_size' to the current chunk back to the mem pool. This can
-  /// only be used to return either all or part of the previous allocation returned
-  /// by Allocate().
-  void ReturnPartialAllocation(int byte_size);
-
-  /// Makes all allocated chunks available for re-use, but doesn't delete any chunks.
-  void Clear();
-
-  /// Deletes all allocated chunks. FreeAll() or AcquireData() must be called for
-  /// each mem pool
-  void FreeAll();
-
-  /// Absorb all chunks that hold data from src. If keep_current is true, let src hold on
-  /// to its last allocated chunk that contains data.
-  /// All offsets handed out by calls to GetCurrentOffset() for 'src' become invalid.
-  void AcquireData(ChunkedAllocator* src, bool keep_current);
-
-  std::string DebugString();
-
-  int64_t total_allocated_bytes() const { return total_allocated_bytes_; }
-  int64_t peak_allocated_bytes() const { return peak_allocated_bytes_; }
-  int64_t total_reserved_bytes() const { return total_reserved_bytes_; }
-
-  /// Return sum of chunk_sizes_.
-  int64_t GetTotalChunkSizes() const;
-
- private:
-  friend class ChunkedAllocatorTest;
-  static const int INITIAL_CHUNK_SIZE = 4 * 1024;
-
-  /// The maximum size of chunk that should be allocated. Allocations larger than this
-  /// size will get their own individual chunk.
-  static const int MAX_CHUNK_SIZE = 1024 * 1024;
-
-  struct ChunkInfo {
-    uint8_t* data;  // Owned by the ChunkInfo.
-    int64_t size;   // in bytes
-
-    /// bytes allocated via Allocate() in this chunk
-    int64_t allocated_bytes;
-
-    explicit ChunkInfo(int64_t size, uint8_t* buf);
-
-    ChunkInfo() : data(nullptr), size(0), allocated_bytes(0) {}
-  };
-
-  /// chunk from which we served the last Allocate() call;
-  /// always points to the last chunk that contains allocated data;
-  /// chunks 0..current_chunk_idx_ are guaranteed to contain data
-  /// (chunks_[i].allocated_bytes > 0 for i: 0..current_chunk_idx_);
-  /// -1 if no chunks present
-  int current_chunk_idx_;
-
-  /// The size of the next chunk to allocate.
-  int64_t next_chunk_size_;
-
-  /// sum of allocated_bytes_
-  int64_t total_allocated_bytes_;
-
-  /// Maximum number of bytes allocated from this pool at one time.
-  int64_t peak_allocated_bytes_;
-
-  /// sum of all bytes allocated in chunks_
-  int64_t total_reserved_bytes_;
-
-  std::vector<ChunkInfo> chunks_;
-
-  ::arrow::MemoryPool* pool_;
-
-  /// Find or allocated a chunk with at least min_size spare capacity and update
-  /// current_chunk_idx_. Also updates chunks_, chunk_sizes_ and allocated_bytes_
-  /// if a new chunk needs to be created.
-  bool FindChunk(int64_t min_size);
-
-  /// Check integrity of the supporting data structures; always returns true but DCHECKs
-  /// all invariants.
-  /// If 'current_chunk_empty' is false, checks that the current chunk contains data.
-  bool CheckIntegrity(bool current_chunk_empty);
-
-  /// Return offset to unoccpied space in current chunk.
-  int GetFreeOffset() const {
-    if (current_chunk_idx_ == -1) return 0;
-    return static_cast<int>(chunks_[current_chunk_idx_].allocated_bytes);
-  }
-
-  template <bool CHECK_LIMIT_FIRST>
-  uint8_t* Allocate(int size);
-};
-
-// File input and output interfaces that translate arrow::Status to exceptions
-
-class PARQUET_EXPORT FileInterface {
- public:
-  virtual ~FileInterface() = default;
-
-  // Close the file
-  virtual void Close() = 0;
-
-  // Return the current position in the file relative to the start
-  virtual int64_t Tell() = 0;
-};
-
-/// It is the responsibility of implementations to mind threadsafety of shared
-/// resources
-class PARQUET_EXPORT RandomAccessSource : virtual public FileInterface {
- public:
-  virtual ~RandomAccessSource() = default;
-
-  virtual int64_t Size() const = 0;
-
-  // Returns bytes read
-  virtual int64_t Read(int64_t nbytes, uint8_t* out) = 0;
-
-  virtual std::shared_ptr<Buffer> Read(int64_t nbytes) = 0;
-
-  virtual std::shared_ptr<Buffer> ReadAt(int64_t position, int64_t nbytes) = 0;
-
-  /// Returns bytes read
-  virtual int64_t ReadAt(int64_t position, int64_t nbytes, uint8_t* out) = 0;
-};
-
-class PARQUET_EXPORT OutputStream : virtual public FileInterface {
- public:
-  virtual ~OutputStream() = default;
-
-  // Copy bytes into the output stream
-  virtual void Write(const uint8_t* data, int64_t length) = 0;
-};
-
-class PARQUET_EXPORT ArrowFileMethods : virtual public FileInterface {
- public:
-  // No-op. Closing the file is the responsibility of the owner of the handle
-  void Close() override;
-
-  int64_t Tell() override;
-
- protected:
-  virtual ::arrow::io::FileInterface* file_interface() = 0;
-};
-
-/// This interface depends on the threadsafety of the underlying Arrow file interface
-class PARQUET_EXPORT ArrowInputFile : public ArrowFileMethods, public RandomAccessSource {
- public:
-  explicit ArrowInputFile(
-      const std::shared_ptr<::arrow::io::ReadableFileInterface>& file);
-
-  int64_t Size() const override;
-
-  // Returns bytes read
-  int64_t Read(int64_t nbytes, uint8_t* out) override;
-
-  std::shared_ptr<Buffer> Read(int64_t nbytes) override;
-
-  std::shared_ptr<Buffer> ReadAt(int64_t position, int64_t nbytes) override;
-
-  /// Returns bytes read
-  int64_t ReadAt(int64_t position, int64_t nbytes, uint8_t* out) override;
-
-  std::shared_ptr<::arrow::io::ReadableFileInterface> file() const { return file_; }
-
-  // Diamond inheritance
-  using ArrowFileMethods::Close;
-  using ArrowFileMethods::Tell;
-
- private:
-  ::arrow::io::FileInterface* file_interface() override;
-  std::shared_ptr<::arrow::io::ReadableFileInterface> file_;
-};
-
-class PARQUET_EXPORT ArrowOutputStream : public ArrowFileMethods, public OutputStream {
- public:
-  explicit ArrowOutputStream(const std::shared_ptr<::arrow::io::OutputStream> file);
-
-  // Copy bytes into the output stream
-  void Write(const uint8_t* data, int64_t length) override;
-
-  std::shared_ptr<::arrow::io::OutputStream> file() { return file_; }
-
-  // Diamond inheritance
-  using ArrowFileMethods::Close;
-  using ArrowFileMethods::Tell;
-
- private:
-  ::arrow::io::FileInterface* file_interface() override;
-  std::shared_ptr<::arrow::io::OutputStream> file_;
-};
-
-class PARQUET_EXPORT InMemoryOutputStream : public OutputStream {
- public:
-  explicit InMemoryOutputStream(
-      ::arrow::MemoryPool* pool = ::arrow::default_memory_pool(),
-      int64_t initial_capacity = kInMemoryDefaultCapacity);
-
-  virtual ~InMemoryOutputStream();
-
-  // Close is currently a no-op with the in-memory stream
-  virtual void Close() {}
-
-  virtual int64_t Tell();
-
-  virtual void Write(const uint8_t* data, int64_t length);
-
-  // Clears the stream
-  void Clear() { size_ = 0; }
-
-  // Get pointer to the underlying buffer
-  const Buffer& GetBufferRef() const { return *buffer_; }
-
-  // Return complete stream as Buffer
-  std::shared_ptr<Buffer> GetBuffer();
-
- private:
-  // Mutable pointer to the current write position in the stream
-  uint8_t* Head();
-
-  std::shared_ptr<ResizableBuffer> buffer_;
-  int64_t size_;
-  int64_t capacity_;
-
-  DISALLOW_COPY_AND_ASSIGN(InMemoryOutputStream);
-};
-
-// ----------------------------------------------------------------------
-// Streaming input interfaces
-
-// Interface for the column reader to get the bytes. The interface is a stream
-// interface, meaning the bytes in order and once a byte is read, it does not
-// need to be read again.
-class InputStream {
- public:
-  // Returns the next 'num_to_peek' without advancing the current position.
-  // *num_bytes will contain the number of bytes returned which can only be
-  // less than num_to_peek at end of stream cases.
-  // Since the position is not advanced, calls to this function are idempotent.
-  // The buffer returned to the caller is still owned by the input stream and must
-  // stay valid until the next call to Peek() or Read().
-  virtual const uint8_t* Peek(int64_t num_to_peek, int64_t* num_bytes) = 0;
-
-  // Identical to Peek(), except the current position in the stream is advanced by
-  // *num_bytes.
-  virtual const uint8_t* Read(int64_t num_to_read, int64_t* num_bytes) = 0;
-
-  // Advance the stream without reading
-  virtual void Advance(int64_t num_bytes) = 0;
-
-  virtual ~InputStream() {}
-
- protected:
-  InputStream() {}
-};
-
-// Implementation of an InputStream when all the bytes are in memory.
-class PARQUET_EXPORT InMemoryInputStream : public InputStream {
- public:
-  InMemoryInputStream(RandomAccessSource* source, int64_t start, int64_t end);
-  explicit InMemoryInputStream(const std::shared_ptr<Buffer>& buffer);
-  virtual const uint8_t* Peek(int64_t num_to_peek, int64_t* num_bytes);
-  virtual const uint8_t* Read(int64_t num_to_read, int64_t* num_bytes);
-
-  virtual void Advance(int64_t num_bytes);
-
- private:
-  std::shared_ptr<Buffer> buffer_;
-  int64_t len_;
-  int64_t offset_;
-};
-
-// Implementation of an InputStream when only some of the bytes are in memory.
-class PARQUET_EXPORT BufferedInputStream : public InputStream {
- public:
-  BufferedInputStream(::arrow::MemoryPool* pool, int64_t buffer_size,
-                      RandomAccessSource* source, int64_t start, int64_t end);
-  virtual const uint8_t* Peek(int64_t num_to_peek, int64_t* num_bytes);
-  virtual const uint8_t* Read(int64_t num_to_read, int64_t* num_bytes);
-
-  virtual void Advance(int64_t num_bytes);
-
- private:
-  std::shared_ptr<ResizableBuffer> buffer_;
-  RandomAccessSource* source_;
-  int64_t stream_offset_;
-  int64_t stream_end_;
-  int64_t buffer_offset_;
-  int64_t buffer_size_;
-};
-
-std::shared_ptr<ResizableBuffer> PARQUET_EXPORT AllocateBuffer(
-    ::arrow::MemoryPool* pool = ::arrow::default_memory_pool(), int64_t size = 0);
-
-}  // namespace parquet
-
-#endif  // PARQUET_UTIL_MEMORY_H
diff --git a/src/parquet/util/schema-util.h b/src/parquet/util/schema-util.h
deleted file mode 100644
index 1c66f67..0000000
--- a/src/parquet/util/schema-util.h
+++ /dev/null
@@ -1,87 +0,0 @@
-// 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.
-
-#ifndef PARQUET_SCHEMA_UTIL_H
-#define PARQUET_SCHEMA_UTIL_H
-
-#include <string>
-#include <unordered_set>
-#include <vector>
-
-#include "parquet/exception.h"
-#include "parquet/schema.h"
-#include "parquet/types.h"
-
-using parquet::LogicalType;
-using parquet::ParquetException;
-using parquet::SchemaDescriptor;
-using parquet::schema::GroupNode;
-using parquet::schema::Node;
-using parquet::schema::NodePtr;
-
-inline bool str_endswith_tuple(const std::string& str) {
-  if (str.size() >= 6) {
-    return str.substr(str.size() - 6, 6) == "_tuple";
-  }
-  return false;
-}
-
-// Special case mentioned in the format spec:
-//   If the name is array or ends in _tuple, this should be a list of struct
-//   even for single child elements.
-inline bool HasStructListName(const GroupNode& node) {
-  return (node.name() == "array" || str_endswith_tuple(node.name()));
-}
-
-// TODO(itaiin): This aux. function is to be deleted once repeated structs are supported
-inline bool IsSimpleStruct(const Node* node) {
-  if (!node->is_group()) return false;
-  if (node->is_repeated()) return false;
-  if (node->logical_type() == LogicalType::LIST) return false;
-  // Special case mentioned in the format spec:
-  //   If the name is array or ends in _tuple, this should be a list of struct
-  //   even for single child elements.
-  auto group = static_cast<const GroupNode*>(node);
-  if (group->field_count() == 1 && HasStructListName(*group)) return false;
-
-  return true;
-}
-
-// Coalesce a list of schema fields indices which are the roots of the
-// columns referred by a list of column indices
-inline bool ColumnIndicesToFieldIndices(const SchemaDescriptor& descr,
-                                        const std::vector<int>& column_indices,
-                                        std::vector<int>* out) {
-  const GroupNode* group = descr.group_node();
-  std::unordered_set<int> already_added;
-  out->clear();
-  for (auto& column_idx : column_indices) {
-    auto field_node = descr.GetColumnRoot(column_idx);
-    auto field_idx = group->FieldIndex(*field_node);
-    if (field_idx < 0) {
-      return false;
-    }
-    auto insertion = already_added.insert(field_idx);
-    if (insertion.second) {
-      out->push_back(field_idx);
-    }
-  }
-
-  return true;
-}
-
-#endif  // PARQUET_SCHEMA_UTIL_H
diff --git a/src/parquet/util/stopwatch.h b/src/parquet/util/stopwatch.h
deleted file mode 100644
index 68cf792..0000000
--- a/src/parquet/util/stopwatch.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// 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.
-
-#ifndef PARQUET_UTIL_STOPWATCH_H
-#define PARQUET_UTIL_STOPWATCH_H
-
-#include <stdio.h>
-#ifndef _MSC_VER
-#include <sys/time.h>
-#endif
-
-#include <ctime>
-#include <iostream>
-
-namespace parquet {
-
-class StopWatch {
- public:
-  StopWatch() {}
-
-  void Start() { gettimeofday(&start_time, 0); }
-
-  // Returns time in nanoseconds.
-  uint64_t Stop() {
-    struct timeval t_time;
-    gettimeofday(&t_time, 0);
-
-    return (1000L * 1000L * 1000L * (t_time.tv_sec - start_time.tv_sec) +
-            (t_time.tv_usec - start_time.tv_usec));
-  }
-
- private:
-  struct timeval start_time;
-};
-
-}  // namespace parquet
-
-#endif
diff --git a/src/parquet/util/test-common.h b/src/parquet/util/test-common.h
deleted file mode 100644
index 4e95870..0000000
--- a/src/parquet/util/test-common.h
+++ /dev/null
@@ -1,208 +0,0 @@
-// 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.
-
-#ifndef PARQUET_UTIL_TEST_COMMON_H
-#define PARQUET_UTIL_TEST_COMMON_H
-
-#include <chrono>
-#include <iostream>
-#include <limits>
-#include <random>
-#include <vector>
-
-#include "parquet/exception.h"
-#include "parquet/types.h"
-
-using std::vector;
-
-namespace parquet {
-
-namespace test {
-
-typedef ::testing::Types<BooleanType, Int32Type, Int64Type, Int96Type, FloatType,
-                         DoubleType, ByteArrayType, FLBAType>
-    ParquetTypes;
-
-class ParquetTestException : public parquet::ParquetException {
-  using ParquetException::ParquetException;
-};
-
-const char* get_data_dir() {
-  const auto result = std::getenv("PARQUET_TEST_DATA");
-  if (!result || !result[0]) {
-    throw ParquetTestException(
-        "Please point the PARQUET_TEST_DATA environment "
-        "variable to the test data directory");
-  }
-  return result;
-}
-
-template <typename T>
-static inline void assert_vector_equal(const vector<T>& left, const vector<T>& right) {
-  ASSERT_EQ(left.size(), right.size());
-
-  for (size_t i = 0; i < left.size(); ++i) {
-    ASSERT_EQ(left[i], right[i]) << i;
-  }
-}
-
-template <typename T>
-static inline bool vector_equal(const vector<T>& left, const vector<T>& right) {
-  if (left.size() != right.size()) {
-    return false;
-  }
-
-  for (size_t i = 0; i < left.size(); ++i) {
-    if (left[i] != right[i]) {
-      std::cerr << "index " << i << " left was " << left[i] << " right was " << right[i]
-                << std::endl;
-      return false;
-    }
-  }
-
-  return true;
-}
-
-template <typename T>
-static vector<T> slice(const vector<T>& values, int start, int end) {
-  if (end < start) {
-    return vector<T>(0);
-  }
-
-  vector<T> out(end - start);
-  for (int i = start; i < end; ++i) {
-    out[i - start] = values[i];
-  }
-  return out;
-}
-
-static inline vector<bool> flip_coins_seed(int n, double p, uint32_t seed) {
-  std::mt19937 gen(seed);
-  std::bernoulli_distribution d(p);
-
-  vector<bool> draws;
-  for (int i = 0; i < n; ++i) {
-    draws.push_back(d(gen));
-  }
-  return draws;
-}
-
-static inline vector<bool> flip_coins(int n, double p) {
-  uint64_t seed = std::chrono::high_resolution_clock::now().time_since_epoch().count();
-  std::mt19937 gen(static_cast<uint32_t>(seed));
-
-  std::bernoulli_distribution d(p);
-
-  vector<bool> draws;
-  for (int i = 0; i < n; ++i) {
-    draws.push_back(d(gen));
-  }
-  return draws;
-}
-
-void random_bytes(int n, uint32_t seed, std::vector<uint8_t>* out) {
-  std::mt19937 gen(seed);
-  std::uniform_int_distribution<int> d(0, 255);
-
-  for (int i = 0; i < n; ++i) {
-    out->push_back(static_cast<uint8_t>(d(gen) & 0xFF));
-  }
-}
-
-void random_bools(int n, double p, uint32_t seed, bool* out) {
-  std::mt19937 gen(seed);
-  std::bernoulli_distribution d(p);
-  for (int i = 0; i < n; ++i) {
-    out[i] = d(gen);
-  }
-}
-
-template <typename T>
-void random_numbers(int n, uint32_t seed, T min_value, T max_value, T* out) {
-  std::mt19937 gen(seed);
-  std::uniform_int_distribution<T> d(min_value, max_value);
-  for (int i = 0; i < n; ++i) {
-    out[i] = d(gen);
-  }
-}
-
-template <>
-void random_numbers(int n, uint32_t seed, float min_value, float max_value, float* out) {
-  std::mt19937 gen(seed);
-  std::uniform_real_distribution<float> d(min_value, max_value);
-  for (int i = 0; i < n; ++i) {
-    out[i] = d(gen);
-  }
-}
-
-template <>
-void random_numbers(int n, uint32_t seed, double min_value, double max_value,
-                    double* out) {
-  std::mt19937 gen(seed);
-  std::uniform_real_distribution<double> d(min_value, max_value);
-  for (int i = 0; i < n; ++i) {
-    out[i] = d(gen);
-  }
-}
-
-void random_Int96_numbers(int n, uint32_t seed, int32_t min_value, int32_t max_value,
-                          Int96* out) {
-  std::mt19937 gen(seed);
-  std::uniform_int_distribution<int32_t> d(min_value, max_value);
-  for (int i = 0; i < n; ++i) {
-    out[i].value[0] = d(gen);
-    out[i].value[1] = d(gen);
-    out[i].value[2] = d(gen);
-  }
-}
-
-void random_fixed_byte_array(int n, uint32_t seed, uint8_t* buf, int len, FLBA* out) {
-  std::mt19937 gen(seed);
-  std::uniform_int_distribution<int> d(0, 255);
-  for (int i = 0; i < n; ++i) {
-    out[i].ptr = buf;
-    for (int j = 0; j < len; ++j) {
-      buf[j] = static_cast<uint8_t>(d(gen) & 0xFF);
-    }
-    buf += len;
-  }
-}
-
-void random_byte_array(int n, uint32_t seed, uint8_t* buf, ByteArray* out, int min_size,
-                       int max_size) {
-  std::mt19937 gen(seed);
-  std::uniform_int_distribution<int> d1(min_size, max_size);
-  std::uniform_int_distribution<int> d2(0, 255);
-  for (int i = 0; i < n; ++i) {
-    int len = d1(gen);
-    out[i].len = len;
-    out[i].ptr = buf;
-    for (int j = 0; j < len; ++j) {
-      buf[j] = static_cast<uint8_t>(d2(gen) & 0xFF);
-    }
-    buf += len;
-  }
-}
-
-void random_byte_array(int n, uint32_t seed, uint8_t* buf, ByteArray* out, int max_size) {
-  random_byte_array(n, seed, buf, out, 0, max_size);
-}
-
-}  // namespace test
-}  // namespace parquet
-
-#endif  // PARQUET_UTIL_TEST_COMMON_H
diff --git a/src/parquet/util/visibility.h b/src/parquet/util/visibility.h
deleted file mode 100644
index 984fac2..0000000
--- a/src/parquet/util/visibility.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// 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.
-
-#ifndef PARQUET_UTIL_VISIBILITY_H
-#define PARQUET_UTIL_VISIBILITY_H
-
-#if defined(_WIN32) || defined(__CYGWIN__)
-#ifdef _MSC_VER
-#pragma warning(push)
-// Disable warning for STL types usage in DLL interface
-// https://web.archive.org/web/20130317015847/http://connect.microsoft.com/VisualStudio/feedback/details/696593/vc-10-vs-2010-basic-string-exports
-#pragma warning(disable : 4275 4251)
-// Disable diamond inheritance warnings
-#pragma warning(disable : 4250)
-// Disable macro redefinition warnings
-#pragma warning(disable : 4005)
-// Disable extern before exported template warnings
-#pragma warning(disable : 4910)
-#endif
-#define PARQUET_EXPORT __declspec(dllexport)
-#define PARQUET_NO_EXPORT
-#else  // Not Windows
-#ifndef PARQUET_EXPORT
-#define PARQUET_EXPORT __attribute__((visibility("default")))
-#endif
-#ifndef PARQUET_NO_EXPORT
-#define PARQUET_NO_EXPORT __attribute__((visibility("hidden")))
-#endif
-#endif  // Non-Windows
-
-// gcc and clang disagree about how to handle template visibility when you have
-// explicit specializations https://llvm.org/bugs/show_bug.cgi?id=24815
-
-#if defined(__clang__)
-#define PARQUET_EXTERN_TEMPLATE extern template class PARQUET_EXPORT
-#else
-#define PARQUET_EXTERN_TEMPLATE extern template class
-#endif
-
-// This is a complicated topic, some reading on it:
-// http://www.codesynthesis.com/~boris/blog/2010/01/18/dll-export-cxx-templates/
-#ifdef _MSC_VER
-#define PARQUET_TEMPLATE_EXPORT PARQUET_EXPORT
-#else
-#define PARQUET_TEMPLATE_EXPORT
-#endif
-
-#endif  // PARQUET_UTIL_VISIBILITY_H
diff --git a/src/parquet/util/windows_compatibility.h b/src/parquet/util/windows_compatibility.h
deleted file mode 100644
index 899590a..0000000
--- a/src/parquet/util/windows_compatibility.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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.
-
-#ifndef PARQUET_UTIL_WINDOWS_COMPATIBILITY
-#define PARQUET_UTIL_WINDOWS_COMPATIBILITY
-
-#ifdef _WIN32
-
-// Windows defines min and max macros that mess up std::min/max
-#ifndef NOMINMAX
-#define NOMINMAX
-#endif
-
-#include <windows.h>
-#include <winsock2.h>
-
-#ifdef OPTIONAL
-#undef OPTIONAL
-#endif
-
-#endif  // _WIN32
-
-#endif  // PARQUET_UTIL_WINDOWS_COMPATIBILITY
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
deleted file mode 100644
index 0705c83..0000000
--- a/tools/CMakeLists.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-# 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.
-
-if (PARQUET_BUILD_EXECUTABLES)
-  set(EXECUTABLE_TOOLS
-    parquet-dump-schema
-    parquet_reader
-    parquet-scan)
-
-  foreach(TOOL ${EXECUTABLE_TOOLS})
-    add_executable(${TOOL} "${TOOL}.cc")
-    target_link_libraries(${TOOL} parquet_static)
-    # Avoid unsetting RPATH when installing
-    set_target_properties(${TOOL} PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE)
-    install(TARGETS ${TOOL} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
-  endforeach(TOOL)
-endif()
diff --git a/tools/parquet-dump-schema.cc b/tools/parquet-dump-schema.cc
deleted file mode 100644
index 1e0239b..0000000
--- a/tools/parquet-dump-schema.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// 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.
-
-#include <iostream>
-
-#include "parquet/api/reader.h"
-#include "parquet/api/schema.h"
-
-int main(int argc, char** argv) {
-  std::string filename = argv[1];
-
-  try {
-    std::unique_ptr<parquet::ParquetFileReader> reader =
-        parquet::ParquetFileReader::OpenFile(filename);
-    PrintSchema(reader->metadata()->schema()->schema_root().get(), std::cout);
-  } catch (const std::exception& e) {
-    std::cerr << "Parquet error: " << e.what() << std::endl;
-    return -1;
-  }
-
-  return 0;
-}
diff --git a/tools/parquet-scan.cc b/tools/parquet-scan.cc
deleted file mode 100644
index ab9363b..0000000
--- a/tools/parquet-scan.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// 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.
-
-#include <ctime>
-#include <iostream>
-#include <list>
-#include <memory>
-
-#include "parquet/api/reader.h"
-
-int main(int argc, char** argv) {
-  if (argc > 4 || argc < 1) {
-    std::cerr << "Usage: parquet-scan [--batch-size=] [--columns=...] <file>"
-              << std::endl;
-    return -1;
-  }
-
-  std::string filename;
-
-  // Read command-line options
-  int batch_size = 256;
-  const std::string COLUMNS_PREFIX = "--columns=";
-  const std::string BATCH_SIZE_PREFIX = "--batch-size=";
-  std::vector<int> columns;
-  int num_columns = 0;
-
-  char *param, *value;
-  for (int i = 1; i < argc; i++) {
-    if ((param = std::strstr(argv[i], COLUMNS_PREFIX.c_str()))) {
-      value = std::strtok(param + COLUMNS_PREFIX.length(), ",");
-      while (value) {
-        columns.push_back(std::atoi(value));
-        value = std::strtok(nullptr, ",");
-        num_columns++;
-      }
-    } else if ((param = std::strstr(argv[i], BATCH_SIZE_PREFIX.c_str()))) {
-      value = std::strtok(param + BATCH_SIZE_PREFIX.length(), " ");
-      if (value) {
-        batch_size = std::atoi(value);
-      }
-    } else {
-      filename = argv[i];
-    }
-  }
-
-  try {
-    double total_time;
-    std::clock_t start_time = std::clock();
-    std::unique_ptr<parquet::ParquetFileReader> reader =
-        parquet::ParquetFileReader::OpenFile(filename);
-
-    int64_t total_rows = parquet::ScanFileContents(columns, batch_size, reader.get());
-
-    total_time = static_cast<double>(std::clock() - start_time) /
-      static_cast<double>(CLOCKS_PER_SEC);
-    std::cout << total_rows << " rows scanned in " << total_time << " seconds."
-              << std::endl;
-  } catch (const std::exception& e) {
-    std::cerr << "Parquet error: " << e.what() << std::endl;
-    return -1;
-  }
-
-  return 0;
-}
diff --git a/tools/parquet_reader.cc b/tools/parquet_reader.cc
deleted file mode 100644
index 34bdfc1..0000000
--- a/tools/parquet_reader.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-// 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.
-
-#include <iostream>
-#include <list>
-#include <memory>
-
-#include "parquet/api/reader.h"
-
-int main(int argc, char** argv) {
-  if (argc > 5 || argc < 2) {
-    std::cerr << "Usage: parquet_reader [--only-metadata] [--no-memory-map] [--json]"
-                 "[--print-key-value-metadata] [--columns=...] <file>"
-              << std::endl;
-    return -1;
-  }
-
-  std::string filename;
-  bool print_values = true;
-  bool print_key_value_metadata = false;
-  bool memory_map = true;
-  bool format_json = false;
-
-  // Read command-line options
-  const std::string COLUMNS_PREFIX = "--columns=";
-  std::list<int> columns;
-
-  char *param, *value;
-  for (int i = 1; i < argc; i++) {
-    if ((param = std::strstr(argv[i], "--only-metadata"))) {
-      print_values = false;
-    } else if ((param = std::strstr(argv[i], "--print-key-value-metadata"))) {
-      print_key_value_metadata = true;
-    } else if ((param = std::strstr(argv[i], "--no-memory-map"))) {
-      memory_map = false;
-    } else if ((param = std::strstr(argv[i], "--json"))) {
-      format_json = true;
-    } else if ((param = std::strstr(argv[i], COLUMNS_PREFIX.c_str()))) {
-      value = std::strtok(param + COLUMNS_PREFIX.length(), ",");
-      while (value) {
-        columns.push_back(std::atoi(value));
-        value = std::strtok(nullptr, ",");
-      }
-    } else {
-      filename = argv[i];
-    }
-  }
-
-  try {
-    std::unique_ptr<parquet::ParquetFileReader> reader =
-        parquet::ParquetFileReader::OpenFile(filename, memory_map);
-    parquet::ParquetFilePrinter printer(reader.get());
-    if (format_json) {
-      printer.JSONPrint(std::cout, columns, filename.c_str());
-    } else {
-      printer.DebugPrint(std::cout, columns, print_values,
-        print_key_value_metadata, filename.c_str());
-    }
-  } catch (const std::exception& e) {
-    std::cerr << "Parquet error: " << e.what() << std::endl;
-    return -1;
-  }
-
-  return 0;
-}