Skip to content

Conversation

kentosugama
Copy link
Contributor

@kentosugama kentosugama commented Sep 22, 2022

Base Library Extension Doc: https://docs.google.com/document/d/1uKouujLL3KueLpqjjFV2gd4dqu_6GYD107WBb6_GSVE/edit

  • Complete unit tests

  • Consider making initCapacity an optional value with a default initial capacity

  • While loop iterations over Arrays may be faster with an iterator due to a compiler optimization

  • In functions where a new buffer is being constructed, have some consistent scheme for how to determine the new buffer's capacity. Should the new buffer have just enough space to hold its element, or be given some insertion leeway?

  • Some class methods can be moved outside of the class since they don't need access to the underlying array

  • Consider behavior of transpose on empty Buffers

  • sort() can be optimized by hoisting helper functions

  • Restore broken methods in Array.mo and Hash.mo

  • Compare with original Buffer class and try to keep some level of backwards compatibility / deprecate old functions

  • Fix naming to be consistent with user friendliness, other classes, and style / interface guide

  • Add user friendly error messages / error checking

  • Cleanup tests

  • Add documentation for each function

  • Add examples for each function (put up as a separate PR)

  • A primitive array tabulate for var arrays would allow some nice optimizations (put up as a separate PR)

  • Profile this class to see if a more scalable dynamic sequence is necessary and to resolve ambiguous design decisions

This last point is related to the RRB Trees, Rope, and Finger Trees data structures that I was discussing before. For various reasons, I am leaning towards an RRB Tree implementation of a scalable sequence structure, if it is necessary. See a talk on this data structure here: https://www.youtube.com/watch?v=sPhpelUfu8Q

@kentosugama kentosugama marked this pull request as ready for review October 10, 2022 19:39
@kentosugama
Copy link
Contributor Author

Apologies that this is such a large PR. I'll definitely keep in mind for the future to break PRs into smaller, more frequent chunks.

};

return true;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, here:

  public func isStrictSuffixOf<X>(suffix : Buffer<X>, buffer : Buffer<X>, equal : (X, X) -> Bool) : Bool {
    if (buffer.size() <= suffix.size()) {
      return false;
    };
    isSuffixOf(suffix, buffer, equal);
  };

luc-blaeser
luc-blaeser previously approved these changes Oct 17, 2022
Copy link
Contributor

@luc-blaeser luc-blaeser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work, lots of functionality. Just had a few small suggestions.

luc-blaeser
luc-blaeser previously approved these changes Oct 18, 2022
Copy link
Contributor

@luc-blaeser luc-blaeser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the changes.

src/Array.mo Outdated
@@ -42,7 +41,7 @@ module {
};
};

/// Sorts the given array according to the `cmp` function.
/// Sorts the given array according to the `compare` function.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Sorts the given array according to the `compare` function.
/// Sorts the given array, in ascending order, according to the `compare` function.

src/Array.mo Outdated
freeze(tmp)
};

/// Sorts the given array in place according to the `cmp` function.
/// Sorts the given array in place according to the `compare` function.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Sorts the given array in place according to the `compare` function.
/// Sorts the given array in place, in ascending order, according to the `compare` function.

src/Buffer.mo Outdated
/// `capacity` is the length of the underyling array that backs this list.
/// `capacity` >= `size` is an invariant for this class.
///
/// Like arrays, elements in the buffer are ordered by indices from 0 to size-1.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Like arrays, elements in the buffer are ordered by indices from 0 to size-1.
/// Like arrays, elements in the buffer are ordered by indices from 0 to `size`-1.

_size += size2;
};

/// Sorts the elements in the buffer according to `compare`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Sorts the elements in the buffer according to `compare`.
/// Sorts the elements in the buffer, in ascending order, according to `compare`.

src/Buffer.mo Outdated
Comment on lines 1273 to 1274
/// If any invocation of `f` produces an #err, returns an #err. Otherwise
/// Returns an #ok containing the new buffer.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// If any invocation of `f` produces an #err, returns an #err. Otherwise
/// Returns an #ok containing the new buffer.
/// If any invocation of `f` produces an `#err`, returns an `#err`. Otherwise
/// Returns an `#ok` containing the new buffer.

src/Buffer.mo Outdated
i := 0;
j := 0;
while (i < subSize and j < size) {
if (equal(subBuffer.get(i), buffer.get(j)) and i == (subSize - 1 : Nat)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth hoisting (subSize - 1 : Nat) out of the loop, computing it just once.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay will do!

It would be cool to have a loop invariant pass for hosting these, since subSize is bound to a let.

src/Buffer.mo Outdated
let size = buffer.size();
if (size == 0) { [var] } else {
let newArray = Prim.Array_init<X>(size, buffer.get(0));
var i = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var i = 0;
var i = 1;

Can't you start from 1 since you've already copied position 0?

src/Buffer.mo Outdated
Prim.trap "Chunk size must be non-zero in chunk";
};

let newBuffer = Buffer<Buffer<X>>(Prim.abs(Prim.floatToInt(Prim.floatCeil(Prim.intToFloat(buffer.size()) / Prim.intToFloat(size)))));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you really need to use floats here. Isn't integer division and remainder enough?

src/Buffer.mo Outdated
// The length of `elements` is increased by `INCREASE_FACTOR` when capacity is reached.
// The length of `elements` is decreased by `DECREASE_FACTOR` when capacity is strictly less than
// `DECREASE_THRESHOLD`.
private let INCREASE_FACTOR = 1.5; // Keep this factor low to minimize cycle limit problem
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The floats make me slightly nervous - could you use a ratio instead? I.e. Integer multiply by 3 and divide by 2 or some other numerator denominator pair?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, will change

crusso
crusso previously approved these changes Oct 18, 2022
Copy link
Contributor

@crusso crusso left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some more suggestions. Lovely work! Next time, submit in smaller morsels - it's hard for a reviewer to take in so much code in one bite.

@kentosugama kentosugama dismissed stale reviews from crusso and luc-blaeser via 77b29a7 October 19, 2022 02:52
src/Buffer.mo Outdated
Prim.abs(Prim.floatToInt(Prim.floatCeil(Prim.intToFloat(oldCapacity) * INCREASE_FACTOR)));
// calculates ceil(oldCapacity * INCREASE_FACTOR) without floats
let product = oldCapacity * INCREASE_FACTOR_NUME;
(product / INCREASE_FACTOR_DENOM) + (if (product % INCREASE_FACTOR_DENOM != 0) { 1 } else { 0 })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
(product / INCREASE_FACTOR_DENOM) + (if (product % INCREASE_FACTOR_DENOM != 0) { 1 } else { 0 })
(product + INCREASE_FACTOR_DENOM - 1 ) / INCREASE_FACTOR_DENOM

Might do the trick as well. @ggreif amirite? I very well may not be

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@crusso yep this should work. Example: ((57 * 7) + 3 - 1) / 3 gives 133.7, 57 * 7/3 = 133.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay will swap out

src/Buffer.mo Outdated
Comment on lines 1595 to 1596
buffer.size() / size +
(if (buffer.size() % size != 0) { 1 } else { 0 })
Copy link
Contributor

@crusso crusso Oct 19, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
buffer.size() / size +
(if (buffer.size() % size != 0) { 1 } else { 0 })
(buffer.size() + size - 1) / size

analogously. But check my arithmetic. (cc @ggreif)

crusso
crusso previously approved these changes Oct 19, 2022
Copy link
Contributor

@crusso crusso left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(but see small refactorings, if correct)

@kentosugama kentosugama merged commit a224e57 into master Oct 21, 2022
@kentosugama kentosugama deleted the extensions branch October 21, 2022 01:42
@ggreif ggreif restored the extensions branch October 21, 2022 11:31
@ggreif
Copy link
Contributor

ggreif commented Oct 21, 2022

I'd like to re-open this as the commits have been removed from master.

@ggreif ggreif mentioned this pull request Oct 21, 2022
16 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants