<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def _compute(self, inputs, dates, assets, mask):
 """ Compute by delegating to self._wrapped_term._compute on sample dates. On non-sample dates, forward-fill from previously-computed samples. """

        to_sample = dates[select_sampling_indices(dates, self._frequency)]
        assert to_sample[0] == dates[0], \
            "Misaligned sampling dates in %s." % type(self).__name__

        real_compute = self._wrapped_term._compute

        # Inputs will contain different kinds of values depending on whether or
        # not we're a windowed computation.

        # If we're windowed, then `inputs` is a list of iterators of ndarrays.
        # If we're not windowed, then `inputs` is just a list of ndarrays.
        # There are two things we care about doing with the input:
        #   1. Preparing an input to be passed to our wrapped term.
        #   2. Skipping an input if we're going to use an already-computed row.
        # We perform these actions differently based on the expected kind of
        # input, and we encapsulate these actions with closures so that we
        # don't clutter the code below with lots of branching.
        if self.windowed:
            # If we're windowed, inputs are stateful AdjustedArrays.  We don't
            # need to do any preparation before forwarding to real_compute, but
            # we need to call `next` on them if we want to skip an iteration.
            def prepare_inputs():
                return inputs

            def skip_this_input():
                for w in inputs:
                    next(w)
        else:
            # If we're not windowed, inputs are just ndarrays.  We need to
            # slice out a single row when forwarding to real_compute, but we
            # don't need to do anything to skip an input.
            def prepare_inputs():
                # i is the loop iteration variable below.
                return [a[[i]] for a in inputs]

            def skip_this_input():
                pass

        results = []
        samples = iter(to_sample)
        next_sample = next(samples)
        for i, compute_date in enumerate(dates):
            if next_sample == compute_date:
                results.append(
                    real_compute(
                        prepare_inputs(),
                        dates[i:i + 1],
                        assets,
                        mask[i:i + 1],
                    )
                )
                try:
                    next_sample = next(samples)
                except StopIteration:
                    # No more samples to take. Set next_sample to Nat, which
                    # compares False with any other datetime.
                    next_sample = pd_NaT
            else:
                skip_this_input()
                # Copy results from previous sample period.
                results.append(results[-1])

        # We should have exhausted our sample dates.
        try:
            next_sample = next(samples)
        except StopIteration:
            pass
        else:
            raise AssertionError("Unconsumed sample date: %s" % next_sample)

        # Concatenate stored results.
        return vstack(results)