CountAccumulator.java
/*
** Module : CountAccumulator.java
** Abstract : Accumulator implementation which counts loop iterations
**
** Copyright (c) 2004-2022, Golden Code Development Corporation.
**
** -#- -I- --Date-- --JPRM-- -----------------------------------Description-----------------------------------
** 001 ECF 20051227 @23780 Created initial version. Counts iterations of
** a loop. Statistics are maintained for both
** the full count and for the current break
** group.
** 002 ECF 20060104 @23815 Consolidated constructors. Separate ctors
** which accepted a FieldReference and an
** Expression were replaced with a single ctor
** which accepts a Resolvable data source.
** 003 ECF 20060111 @23863 Added constructors for primitive types. These
** are needed to support accumulation of literal
** values.
** 004 ECF 20060118 @23984 Added support for break groups. Made mods to
** support new base class architecture.
** 005 ECF 20060503 @25950 Added support for accumulation using external
** data sources. Added features required by code
** converted from aggregators in display
** statements.
** 006 ECF 20060615 @27354 Initialize and reset data sources to unknown
** value. This is consistent with Progress.
** 007 GES 20060830 @28983 Removed H006 and moved back to a zero based
** approach. The count variable can never be
** unknown and is not accessed directly so there
** is no reason to use a wrapper. By default, if
** one has a CONDITIONAL accumulate stmt an
** accumulator is initialized to zero so that
** the accum function will return zero and not
** unknown even if the condition never occurs
** (so that the accumulate stmt is never called
** before the accum function is used to query
** the accumulated result). There must have been
** some case which H006 was designed to fix but
** at this time that case cannot be found AND
** it is certainly not correct for the default
** result. In the case that an accumulate does
** occur, the accumulated datum is ignored and
** the outcome can never be unknown! So at this
** time, the unknown value processing seems to
** be OK.
** 008 ECF 20070627 @34322 Ensure safe result is returned if no data has
** been accumulated. Added safety ctor and
** removed unused ctor variants. Reworked inner
** Data class. New implementation ensures the
** proper default result (either unknown value or
** 0) is returned, depending upon how the
** accumulator has been initialized and used.
** 009 CA 20080213 @37132 Added Data.deepCopy and Data.assign method
** implementation. Added new constructor -
** CountAccumulator(Resolvable, boolean) used
** by Accumulator.deepCopy() to instantiate a new
** accumulator of this type without registering
** to AccumulatorManager or TransactionManager.
** 010 CA 20080326 @37833 On instantiation, the accumulator is set to
** unknown; the accumulator will be reset only
** when a block which uses it is entered.
** 011 ECF 20080702 @39027 Refactored constructors. This was done to
** support conversion changes made to fix a
** memory leak in the framework.
** 012 GES 20080917 @39851 Minor class name change. Also changed the
** default scope level to NEXT instead of
** CURRENT.
** 013 CA 20160721 Cleaned up the c'tors - all accumulators register in the next scope,
** as they are defined and created as instance fields.
** 014 CA 20220514 Accumulators can be explicitly assigned via their associated variable - added
** stubbed setters.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.util;
/**
* A simple accumulator implementation which counts the total number of loop
* iterations performed, as well as the number of loop iterations performed
* within the current break group. Results are retrieved using one of the
* <code>getResult</code> method variants.
*/
public final class CountAccumulator
extends Accumulator
{
/** Relative weight of this accumulator type for sorting purposes */
static final int WEIGHT = TotalAccumulator.WEIGHT + 1;
/**
* Constructor which stores no data source. This instance expects to be
* fed data from an external source via its <code>accumulate</code>
* method. The accumulator is registered with the AccumulatorManager and
* the TransactionManager in the next scope.
*/
public CountAccumulator()
{
super();
}
/**
* Constructor which stores a <code>Resolvable</code> as the accumulator's
* data source. When an iteration occurs, the accumulator gathers its data
* by resolving the current value of the data source. The accumulator is
* registered with the AccumulatorManager and the TransactionManager, in the next scope.
*
* @param dataSource
* Data source from which data is collected.
* @param register
* This flag will be <code>false</code> only if a copy object is instantiated.
* Because we use the copy only for roll-back purposes, we do not need to add it to
* the TransactionManager or AccumulatorManager.
*/
public CountAccumulator(Resolvable dataSource, boolean register)
{
super(dataSource, register);
}
/**
* Get the full result of all accumulations so far for this accumulator,
* across all break groups.
*
* @return Current full result.
*/
public BaseDataType getFullResult()
{
return getResult(null);
}
/**
* Get the current subgroup result for the first registered break group in
* this accumulator. Subsequent break groups, if any, are ignored.
*
* @return Subgroup result for first registered break group, or
* <code>null</code> if no subgroups are being tracked by this
* accumulator.
*/
public BaseDataType getSubResult()
{
Resolvable key = getFirstBreakGroupKey();
if (key == null)
{
return null;
}
return getResult(key);
}
/**
* Get the label associated with this accumulator type, for use in the UI.
*
* @return Label associated with this accumulator type.
*/
public String getLabel()
{
return "COUNT";
}
/**
* Get the relative weight associated with this accumulator type, for use
* in sorting accumulator instances of different types according to their
* natural display order.
*
* @return An integer which represents this accumulator's sorting weight
* relative to other accumulator types.
*/
public int getWeight()
{
return WEIGHT;
}
/**
* Assign this accumulator's value.
*
* @param v
* The new value.
*/
public void setResult(long v)
{
UnimplementedFeature.missing("Accumulator assignment is not supported: COUNT");
}
/**
* Assign this accumulator's value.
*
* @param v
* The new value.
*/
public void setResult(NumberType v)
{
UnimplementedFeature.missing("Accumulator assignment is not supported: COUNT");
}
/**
* Get the full count of iterations performed for the enclosing loop.
*
* @return Total number of iterations performed.
*/
public integer getResult()
{
return getResult(null);
}
/**
* Get the count of iterations performed for the enclosing loop, but only
* since the current break group counter was last reset.
*
* @param breakGroupKey
* Key identifying the break group for which the data is desired.
*
* @return Iteration count since the specified break group counter was
* last reset.
*/
public integer getResult(Resolvable breakGroupKey)
{
return (integer) calculate(breakGroupKey);
}
/**
* Create a data bundle which understands how to calculate an iteration
* count.
*
* @return An instance of {@link CountAccumulator.Data}.
*/
protected DataBundle createDataBundle()
{
return (new Data());
}
/**
* A <code>DataBundle</code> implementation which keeps a running iteration
* count, and returns it upon request.
*/
private class Data
implements DataBundle
{
/** Iteration counter. */
private integer count = null;
/**
* Construct an instance of this class, setting the starting total to
* either unknown value or 0, depending upon whether the enclosing
* accumulator is initialized for use.
*/
private Data()
{
count = new integer();
}
/**
* Reset (to zero) the counter variable, in preparation for beginning
* a new break group.
*/
public void reset()
{
count = new integer(0);
}
/**
* Increment both the iteration count.
*
* @param datum
* Datum to be accumulated; ignored in this case, since it is
* only the fact that the loop iterated which is important.
*/
public void accumulate(BaseDataType datum)
{
count.increment();
}
/**
* Return the current iteration count.
*
* @return Iteration count (zero if no {@link #accumulate} ever
* occurred).
*/
public BaseDataType calculate()
{
return count.duplicate();
}
/**
* This is a form of a copy constructor that makes a deep copy of the
* current instance and returns this copy as a new instance of the same
* class.
*
* @return An instance of the same class whose data is identical to
* that of this instance.
*/
public Undoable deepCopy()
{
Data copy = new Data();
copy.count = (integer) this.count.deepCopy();
return copy;
}
/**
* Sets the state of this instance based on the state of the passed instance.
*
* @param value
* The instance from which to copy state.
*/
public void assign(Undoable value)
{
Data copy = (Data) value;
this.count.assign(copy.count);
}
}
}