1 /*
  2  *  Copyright (c) 2019, 2023, 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.internal.foreign.layout;
 27 
 28 import jdk.internal.foreign.Utils;
 29 
 30 import java.lang.foreign.GroupLayout;
 31 import java.lang.foreign.MemoryLayout;
 32 import java.lang.foreign.SequenceLayout;
 33 import java.lang.foreign.StructLayout;
 34 import java.lang.foreign.UnionLayout;
 35 import java.lang.foreign.ValueLayout;
 36 import java.util.Objects;
 37 import java.util.Optional;
 38 
 39 public abstract sealed class AbstractLayout<L extends AbstractLayout<L> & MemoryLayout>
 40         permits AbstractGroupLayout, PaddingLayoutImpl, SequenceLayoutImpl, ValueLayouts.AbstractValueLayout {
 41 
 42     private final long byteSize;
 43     private final long byteAlignment;
 44     private final Optional<String> name;
 45 
 46     AbstractLayout(long byteSize, long byteAlignment, Optional<String> name) {
 47         this.byteSize = MemoryLayoutUtil.requireByteSizeValid(byteSize, true);
 48         this.byteAlignment = requirePowerOfTwoAndGreaterOrEqualToOne(byteAlignment);
 49         this.name = Objects.requireNonNull(name);
 50     }
 51 
 52     public final L withName(String name) {
 53         return dup(byteAlignment(), Optional.of(name));
 54     }
 55 
 56     public final L withoutName() {
 57         return dup(byteAlignment(), Optional.empty());
 58     }
 59 
 60     public final Optional<String> name() {
 61         return name;
 62     }
 63 
 64     public L withByteAlignment(long byteAlignment) {
 65         return dup(byteAlignment, name);
 66     }
 67 
 68     public final long byteAlignment() {
 69         return byteAlignment;
 70     }
 71 
 72     public final long byteSize() {
 73         return byteSize;
 74     }
 75 
 76     public boolean hasNaturalAlignment() {
 77         return byteSize == byteAlignment;
 78     }
 79 
 80     // the following methods have to copy the same Javadoc as in MemoryLayout, or subclasses will just show
 81     // the Object methods javadoc
 82 
 83     /**
 84      * {@return the hash code value for this layout}
 85      */
 86     @Override
 87     public int hashCode() {
 88         return Objects.hash(name, byteSize, byteAlignment);
 89     }
 90 
 91     /**
 92      * Compares the specified object with this layout for equality. Returns {@code true} if and only if the specified
 93      * object is also a layout, and it is equal to this layout. Two layouts are considered equal if they are of
 94      * the same kind, have the same size, name and alignment constraints. Furthermore, depending on the layout kind, additional
 95      * conditions must be satisfied:
 96      * <ul>
 97      *     <li>two value layouts are considered equal if they have the same {@linkplain ValueLayout#order() order},
 98      *     and {@linkplain ValueLayout#carrier() carrier}</li>
 99      *     <li>two sequence layouts are considered equal if they have the same element count (see {@link SequenceLayout#elementCount()}), and
100      *     if their element layouts (see {@link SequenceLayout#elementLayout()}) are also equal</li>
101      *     <li>two group layouts are considered equal if they are of the same type (see {@link StructLayout},
102      *     {@link UnionLayout}) and if their member layouts (see {@link GroupLayout#memberLayouts()}) are also equal</li>
103      * </ul>
104      *
105      * @param other the object to be compared for equality with this layout.
106      * @return {@code true} if the specified object is equal to this layout.
107      */
108     @Override
109     public boolean equals(Object other) {
110         return other instanceof AbstractLayout<?> otherLayout &&
111                 name.equals(otherLayout.name) &&
112                 byteSize == otherLayout.byteSize &&
113                 byteAlignment == otherLayout.byteAlignment;
114     }
115 
116     /**
117      * {@return the string representation of this layout}
118      */
119     @Override
120     public abstract String toString();
121 
122     abstract L dup(long byteAlignment, Optional<String> name);
123 
124     String decorateLayoutString(String s) {
125         if (name().isPresent()) {
126             s = String.format("%s(%s)", s, name().get());
127         }
128         if (!hasNaturalAlignment()) {
129             s = byteAlignment() + "%" + s;
130         }
131         return s;
132     }
133 
134     private static long requirePowerOfTwoAndGreaterOrEqualToOne(long value) {
135         if (!Utils.isPowerOfTwo(value) || // value must be a power of two
136                 value < 1) { // value must be greater or equal to 1
137             throw new IllegalArgumentException("Invalid alignment: " + value);
138         }
139         return value;
140     }
141 
142 }