1 /*
   2  *  Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
   3  *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  *  This code is free software; you can redistribute it and/or modify it
   6  *  under the terms of the GNU General Public License version 2 only, as
   7  *  published by the Free Software Foundation.  Oracle designates this
   8  *  particular file as subject to the "Classpath" exception as provided
   9  *  by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  *  This code is distributed in the hope that it will be useful, but WITHOUT
  12  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  *  version 2 for more details (a copy is included in the LICENSE file that
  15  *  accompanied this code).
  16  *
  17  *  You should have received a copy of the GNU General Public License version
  18  *  2 along with this work; if not, write to the Free Software Foundation,
  19  *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  *   Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  *  or visit www.oracle.com if you need additional information or have any
  23  *  questions.
  24  *
  25  */
  26 package jdk.incubator.foreign;
  27 
  28 import java.lang.constant.ConstantDescs;
  29 import java.lang.constant.DynamicConstantDesc;
  30 import java.util.Objects;
  31 import java.util.Optional;
  32 import java.util.OptionalLong;
  33 
  34 /**
  35  * A sequence layout. A sequence layout is used to denote a repetition of a given layout, also called the sequence layout's <em>element layout</em>.
  36  * The repetition count, where it exists (e.g. for <em>finite</em> sequence layouts) is said to be the the sequence layout's <em>element count</em>.
  37  * A finite sequence layout can be thought of as a group layout where the sequence layout's element layout is repeated a number of times
  38  * that is equal to the sequence layout's element count. In other words this layout:
  39  *
  40  * <pre>{@code
  41 MemoryLayout.ofSequence(3, MemoryLayout.ofValueBits(32, ByteOrder.BIG_ENDIAN));
  42  * }</pre>
  43  *
  44  * is equivalent to the following layout:
  45  *
  46  * <pre>{@code
  47 MemoryLayout.ofStruct(
  48     MemoryLayout.ofValueBits(32, ByteOrder.BIG_ENDIAN),
  49     MemoryLayout.ofValueBits(32, ByteOrder.BIG_ENDIAN),
  50     MemoryLayout.ofValueBits(32, ByteOrder.BIG_ENDIAN));
  51  * }</pre>
  52  *
  53  * <p>
  54  * This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>
  55  * class; use of identity-sensitive operations (including reference equality
  56  * ({@code ==}), identity hash code, or synchronization) on instances of
  57  * {@code SequenceLayout} may have unpredictable results and should be avoided.
  58  * The {@code equals} method should be used for comparisons.
  59  *
  60  * @implSpec
  61  * This class is immutable and thread-safe.
  62  */
  63 public final class SequenceLayout extends AbstractLayout {
  64 
  65     private final OptionalLong elemCount;
  66     private final MemoryLayout elementLayout;
  67 
  68     SequenceLayout(OptionalLong elemCount, MemoryLayout elementLayout) {
  69         this(elemCount, elementLayout, elementLayout.bitAlignment(), Optional.empty());
  70     }
  71 
  72     SequenceLayout(OptionalLong elemCount, MemoryLayout elementLayout, long alignment, Optional<String> name) {
  73         super(elemCount.isPresent() && AbstractLayout.optSize(elementLayout).isPresent() ?
  74                 OptionalLong.of(elemCount.getAsLong() * elementLayout.bitSize()) :
  75                 OptionalLong.empty(), alignment, name);
  76         this.elemCount = elemCount;
  77         this.elementLayout = elementLayout;
  78     }
  79 
  80     /**
  81      * Returns the element layout associated with this sequence layout.
  82      *
  83      * @return The element layout associated with this sequence layout.
  84      */
  85     public MemoryLayout elementLayout() {
  86         return elementLayout;
  87     }
  88 
  89     /**
  90      * Returns the element count of this sequence layout (if any).
  91      *
  92      * @return the element count of this sequence layout (if any).
  93      */
  94     public OptionalLong elementCount() {
  95         return elemCount;
  96     }
  97 
  98     @Override
  99     public String toString() {
 100         return decorateLayoutString(String.format("[%s:%s]",
 101                 elemCount.isPresent() ? elemCount.getAsLong() : "", elementLayout));
 102     }
 103 
 104     @Override
 105     public boolean equals(Object other) {
 106         if (this == other) {
 107             return true;
 108         }
 109         if (!super.equals(other)) {
 110             return false;
 111         }
 112         if (!(other instanceof SequenceLayout)) {
 113             return false;
 114         }
 115         SequenceLayout s = (SequenceLayout)other;
 116         return elemCount.equals(s.elemCount) && elementLayout.equals(s.elementLayout);
 117     }
 118 
 119     @Override
 120     public int hashCode() {
 121         return Objects.hash(super.hashCode(), elemCount, elementLayout);
 122     }
 123 
 124     @Override
 125     SequenceLayout dup(long alignment, Optional<String> name) {
 126         return new SequenceLayout(elementCount(), elementLayout, alignment, name);
 127     }
 128 
 129     @Override
 130     boolean hasNaturalAlignment() {
 131         return alignment == elementLayout.bitAlignment();
 132     }
 133 
 134     @Override
 135     public Optional<DynamicConstantDesc<SequenceLayout>> describeConstable() {
 136         return elemCount.isPresent() ?
 137                 Optional.of(DynamicConstantDesc.ofNamed(ConstantDescs.BSM_INVOKE, "value",
 138                         CD_SEQUENCE_LAYOUT, MH_SIZED_SEQUENCE, elemCount.getAsLong(), elementLayout.describeConstable().get())) :
 139                 Optional.of(DynamicConstantDesc.ofNamed(ConstantDescs.BSM_INVOKE, "value",
 140                         CD_SEQUENCE_LAYOUT, MH_UNSIZED_SEQUENCE, elementLayout.describeConstable().get()));
 141     }
 142 
 143     //hack: the declarations below are to make javadoc happy; we could have used generics in AbstractLayout
 144     //but that causes issues with javadoc, see JDK-8224052
 145 
 146     /**
 147      * {@inheritDoc}
 148      */
 149     @Override
 150     public SequenceLayout withName(String name) {
 151         return (SequenceLayout)super.withName(name);
 152     }
 153 
 154     /**
 155      * {@inheritDoc}
 156      */
 157     @Override
 158     public SequenceLayout withBitAlignment(long alignmentBits) {
 159         return (SequenceLayout)super.withBitAlignment(alignmentBits);
 160     }
 161 }