2 libparted - a library for manipulating disk partitions
3 Copyright (C) 2000, 2007-2012 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * \addtogroup PedAlignment
26 * \brief Alignment constraint model.
28 * This part of libparted models alignment constraints.
35 #include <parted/parted.h>
36 #include <parted/debug.h>
37 #include <parted/natmath.h>
39 /* Arrrghhh! Why doesn't C have tuples? */
41 PedSector gcd; /* "converges" to the gcd */
46 static const PedAlignment _any = {
51 const PedAlignment* ped_alignment_any = &_any;
52 const PedAlignment* ped_alignment_none = NULL;
54 /* This function returns "a mod b", the way C should have done it!
55 * Mathematicians prefer -3 mod 4 to be 3. Reason: division by N
56 * is all about adding or subtracting N, and we like our remainders
57 * to be between 0 and N - 1.
60 abs_mod (PedSector a, PedSector b)
68 /* Rounds a number down to the closest number that is a multiple of
72 ped_round_down_to (PedSector sector, PedSector grain_size)
74 return sector - abs_mod (sector, grain_size);
77 /* Rounds a number up to the closest number that is a multiple of
81 ped_round_up_to (PedSector sector, PedSector grain_size)
83 if (sector % grain_size)
84 return ped_round_down_to (sector, grain_size) + grain_size;
89 /* Rounds a number to the closest number that is a multiple of grain_size. */
91 ped_round_to_nearest (PedSector sector, PedSector grain_size)
93 if (sector % grain_size > grain_size/2)
94 return ped_round_up_to (sector, grain_size);
96 return ped_round_down_to (sector, grain_size);
99 /* This function returns the largest number that divides both a and b.
100 * It uses the ancient Euclidean algorithm.
103 ped_greatest_common_divisor (PedSector a, PedSector b)
108 /* Put the arguments in the "right" format. (Recursive calls made by
109 * this function are always in the right format.)
112 return ped_greatest_common_divisor (b, a);
115 return ped_greatest_common_divisor (b, a % b);
121 * Initialize a preallocated piece of memory for an alignment object
122 * (used by PedConstraint).
124 * The object will represent all sectors \e s for which the equation
125 * <tt>s = offset + X * grain_size</tt> holds.
128 ped_alignment_init (PedAlignment* align, PedSector offset, PedSector grain_size)
130 PED_ASSERT (align != NULL);
136 align->offset = abs_mod (offset, grain_size);
138 align->offset = offset;
139 align->grain_size = grain_size;
145 * Return an alignment object (used by PedConstraint), representing all
146 * PedSector's that are of the form <tt>offset + X * grain_size</tt>.
149 ped_alignment_new (PedSector offset, PedSector grain_size)
153 align = (PedAlignment*) ped_malloc (sizeof (PedAlignment));
157 if (!ped_alignment_init (align, offset, grain_size))
158 goto error_free_align;
169 * Free up memory associated with \p align.
172 ped_alignment_destroy (PedAlignment* align)
178 * Return a duplicate of \p align.
181 ped_alignment_duplicate (const PedAlignment* align)
185 return ped_alignment_new (align->offset, align->grain_size);
188 /* the extended Euclid algorithm.
194 * gcd, x and y, such that:
196 * gcd = greatest common divisor of a and b
199 static EuclidTriple _GL_ATTRIBUTE_PURE
200 extended_euclid (int a, int b)
212 tmp = extended_euclid (b, a % b);
213 result.gcd = tmp.gcd;
215 result.y = tmp.x - (a/b) * tmp.y;
220 * This function computes a PedAlignment object that describes the
221 * intersection of two alignments. That is, a sector satisfies the
222 * new alignment object if and only if it satisfies both of the original
223 * ones. (See ped_alignment_is_aligned() for the meaning of "satisfies")
225 * Apart from the trivial cases (where one or both of the alignment objects
226 * constraints have no sectors that satisfy them), this is what we're trying to
228 * - two input constraints: \p a and \p b.
229 * - the new grain_size is going to be the lowest common multiple of
230 * \p a->grain_size and \p b->grain_size
231 * - hard part - solve the simultaneous equations, for offset, where offset,
232 * X and Y are variables. (Note: offset can be obtained from either X or Y,
233 * by substituing into either equation)
236 * offset = \p a->offset + X * \p a->grain_size (1)
237 * offset = \p b->offset + Y * \p b->grain_size (2)
246 * => Ao + X*Ag = Bo + Y*Bg (1) = (2)
247 * X*Ag - Y*Bg = Bo - Ao (3)
250 * As it turns out, there only exists a solution if (Bo - Ao) is a multiple
251 * of the GCD of Ag and Bg. Reason: all linear combinations of Ag and Bg are
252 * multiples of the GCD.
258 * = A * (\p a * gcd) + B * (\p b * gcd)
259 * = gcd * (A * \p a + B * \p b)
262 * gcd is a factor of the linear combination. QED
264 * Anyway, \p a * Ag + \p b * Bg = gcd can be solved (for \p a, \p b and gcd)
265 * with Euclid's extended algorithm. Then, we just multiply through by
266 * (Bo - Ao) / gcd to get (3).
270 * A * Ag + B * Bg = gcd
271 * A*(Bo-Ao)/gcd * Ag + B(Bo-Ao)/gcd * Bg = gcd * (Bo-Ao)/gcd
272 * X*Ag - Y*Bg = Bo - Ao (3)
275 * Y = - B*(Bo-Ao)/gcd
281 * = Ao + A*(Bo-Ao)/gcd*Ag
283 * = Bo - B*(Bo-Ao)/gcd*Ag
286 * Thanks go to Nathan Hurst (njh@hawthorn.csse.monash.edu.au) for figuring
287 * this algorithm out :-)
289 * \note Returned \c NULL is a valid PedAlignment object, and can be used
290 for ped_alignment_*() function.
292 * \return a PedAlignment on success, \c NULL on failure
295 ped_alignment_intersect (const PedAlignment* a, const PedAlignment* b)
297 PedSector new_grain_size;
298 PedSector new_offset;
299 PedSector delta_on_gcd;
300 EuclidTriple gcd_factors;
306 /*PED_DEBUG (0x10, "intersecting alignments (%d,%d) and (%d,%d)",
307 a->offset, a->grain_size, b->offset, b->grain_size);
310 if (a->grain_size < b->grain_size) {
311 const PedAlignment* tmp;
312 tmp = a; a = b; b = tmp;
315 /* weird/trivial case: where the solution space for "a" or "b" is
316 * either empty or contains exactly one solution
318 if (a->grain_size == 0 && b->grain_size == 0) {
319 if (a->offset == b->offset)
320 return ped_alignment_duplicate (a);
326 gcd_factors = extended_euclid (a->grain_size, b->grain_size);
328 delta_on_gcd = (b->offset - a->offset) / gcd_factors.gcd;
329 new_offset = a->offset + gcd_factors.x * delta_on_gcd * a->grain_size;
330 new_grain_size = a->grain_size * b->grain_size / gcd_factors.gcd;
332 /* inconsistency => no solution */
334 != b->offset - gcd_factors.y * delta_on_gcd * b->grain_size)
337 return ped_alignment_new (new_offset, new_grain_size);
340 /* This function returns the sector closest to "sector" that lies inside
341 * geom and satisfies the alignment constraint.
343 static PedSector _GL_ATTRIBUTE_PURE
344 _closest_inside_geometry (const PedAlignment* align, const PedGeometry* geom,
347 PED_ASSERT (align != NULL);
349 if (!align->grain_size) {
350 if (ped_alignment_is_aligned (align, geom, sector)
351 && (!geom || ped_geometry_test_sector_inside (geom,
358 if (sector < geom->start)
359 sector += ped_round_up_to (geom->start - sector,
361 if (sector > geom->end)
362 sector -= ped_round_up_to (sector - geom->end,
365 if (!ped_geometry_test_sector_inside (geom, sector))
371 * This function returns the closest sector to \p sector that lies inside
372 * \p geom that satisfies the given alignment constraint \p align. It prefers
373 * sectors that are beyond \p sector (are not smaller than \p sector),
374 * but does not guarantee that this.
376 * \return a PedSector on success, \c -1 on failure
379 ped_alignment_align_up (const PedAlignment* align, const PedGeometry* geom,
384 PED_ASSERT (align != NULL);
386 if (!align->grain_size)
387 result = align->offset;
389 result = ped_round_up_to (sector - align->offset,
394 result = _closest_inside_geometry (align, geom, result);
399 * This function returns the closest sector to \p sector that lies inside
400 * \p geom that satisfies the given alignment constraint \p align. It prefers
401 * sectors that are before \p sector (are not larger than \p sector),
402 * but does not guarantee that this.
404 * \return a PedSector on success, \c -1 on failure
407 ped_alignment_align_down (const PedAlignment* align, const PedGeometry* geom,
412 PED_ASSERT (align != NULL);
414 if (!align->grain_size)
415 result = align->offset;
417 result = ped_round_down_to (sector - align->offset,
422 result = _closest_inside_geometry (align, geom, result);
426 /* Returns either a or b, depending on which is closest to "sector". */
428 closest (PedSector sector, PedSector a, PedSector b)
435 if (abs (sector - a) < abs (sector - b))
442 * This function returns the sector that is closest to \p sector,
443 * satisfies the \p align constraint and lies inside \p geom.
445 * \return a PedSector on success, \c -1 on failure
448 ped_alignment_align_nearest (const PedAlignment* align, const PedGeometry* geom,
451 PED_ASSERT (align != NULL);
453 return closest (sector, ped_alignment_align_up (align, geom, sector),
454 ped_alignment_align_down (align, geom, sector));
458 * This function returns 1 if \p sector satisfies the alignment
459 * constraint \p align and lies inside \p geom.
461 * \return \c 1 on success, \c 0 on failure
464 ped_alignment_is_aligned (const PedAlignment* align, const PedGeometry* geom,
470 if (geom && !ped_geometry_test_sector_inside (geom, sector))
473 if (align->grain_size)
474 return (sector - align->offset) % align->grain_size == 0;
476 return sector == align->offset;