askoa commented on code in PR #3817:
URL: https://github.com/apache/arrow-rs/pull/3817#discussion_r1130210322


##########
arrow-buffer/src/buffer/run.rs:
##########
@@ -0,0 +1,200 @@
+// 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.
+
+use crate::buffer::ScalarBuffer;
+use crate::ArrowNativeType;
+
+/// A slice-able buffer of monotonically increasing, positive integers used to 
store run-ends
+///
+/// # Logical vs Physical
+///
+/// A [`RunEndBuffer`] is used to encode runs of the same value, the index of 
each run is
+/// called the physical index. The logical index is then the corresponding 
index in the logical
+/// run-encoded array, i.e. a single run of length `3`, would have the logical 
indices `0..3`.
+///
+/// Each value in [`RunEndBuffer::values`] is the cumulative length of all 
runs in the
+/// logical array, up to that physical index.
+///
+/// Consider a [`RunEndBuffer`] containing `[3, 4, 6]`. The maximum physical 
index is `2`,
+/// as there are `3` values, and the maximum logical index is `6`, as the 
maximum run end
+/// is `6`. The physical indices are therefore `[0, 0, 0, 1, 1, 2, 2]`
+///
+/// ```text
+///     ┌─────────┐        ┌─────────┐           ┌─────────┐
+///     │    3    │        │    0    │ ─┬──────▶ │    0    │
+///     ├─────────┤        ├─────────┤  │        ├─────────┤
+///     │    4    │        │    1    │ ─┤ ┌────▶ │    1    │
+///     ├─────────┤        ├─────────┤  │ │      ├─────────┤
+///     │    6    │        │    2    │ ─┘ │ ┌──▶ │    2    │
+///     └─────────┘        ├─────────┤    │ │    └─────────┘
+///      run ends          │    3    │ ───┤ │  physical indices
+///                        ├─────────┤    │ │
+///                        │    4    │ ───┘ │
+///                        ├─────────┤      │
+///                        │    5    │ ─────┤
+///                        ├─────────┤      │
+///                        │    6    │ ─────┘
+///                        └─────────┘
+///                      logical indices
+/// ```
+///
+/// # Slicing
+///
+/// In order to provide zero-copy slicing, this container stores a separate 
offset and length
+///
+/// For example, a [`RunEndBuffer`] containing values `[3, 6, 8]` with offset 
and length `4` would
+/// describe the physical indices `1, 1, 2, 2`
+///
+/// For example, a [`RunEndBuffer`] containing values `[6, 8, 9]` with offset 
`2` and length `5`
+/// would describe the physical indices `0, 0, 0, 0, 1`
+///
+/// [Run-End encoded layout]: 
https://arrow.apache.org/docs/format/Columnar.html#run-end-encoded-layout
+#[derive(Debug, Clone)]
+pub struct RunEndBuffer<E: ArrowNativeType> {
+    run_ends: ScalarBuffer<E>,
+    len: usize,
+    offset: usize,
+}
+
+impl<E> RunEndBuffer<E>
+where
+    E: ArrowNativeType,
+{
+    /// Create a new [`RunEndBuffer`] from a [`ScalarBuffer`], an `offset` and 
`len`
+    ///
+    /// # Panics
+    ///
+    /// - `buffer` does not contain strictly increasing values greater than 
zero
+    /// - the last value of `buffer` is less than `offset + len`
+    pub fn new(run_ends: ScalarBuffer<E>, offset: usize, len: usize) -> Self {
+        assert!(
+            run_ends.windows(2).all(|w| w[0] < w[1]),
+            "run-ends not strictly increasing"
+        );
+
+        if len != 0 {
+            assert!(!run_ends.is_empty(), "non-empty slice but empty 
run-ends");
+            let end = E::from_usize(offset.saturating_add(len)).unwrap();
+            assert!(
+                *run_ends.first().unwrap() >= E::usize_as(0),

Review Comment:
   Missed this during original review. Should be `>0` and not `>=0`



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to